| /* |
| * 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, Konstantin M. Anisimov, Igor V. Chebykin |
| * |
| */ |
| |
| #include "MemoryAttribute.h" |
| #include "IpfCodeSelector.h" |
| #include "IpfIrPrinter.h" |
| |
| namespace Jitrino { |
| namespace IPF { |
| |
| #define HEAPBASE (opndManager->getHeapBase()) |
| #define HEAPBASEIMM (opndManager->getHeapBaseImm()) |
| #define VTABLEBASE (opndManager->getVtableBase()) |
| #define VTABLEBASEIMM (opndManager->getVtableBaseImm()) |
| |
| #define IMM32(o) ((I_32)(((Opnd *)(o))->getValue())) |
| #define IMM64(o) ((int64)(((Opnd *)(o))->getValue())) |
| #define IMM32U(o) ((U_32)(((Opnd *)(o))->getValue())) |
| #define IMM64U(o) ((uint64)(((Opnd *)(o))->getValue())) |
| |
| // FP remainder internal helpers (temp solution to be optimized) |
| float remF4 (float v0, float v1); |
| float remF4 (float v0, float v1) { |
| return (float)fmod((double)v0,(double)v1); |
| } |
| |
| double remF8 (double v0, double v1); |
| double remF8 (double v0, double v1) { |
| return fmod(v0,v1); |
| } |
| |
| //===========================================================================// |
| // IpfInstCodeSelector |
| //===========================================================================// |
| |
| IpfInstCodeSelector::IpfInstCodeSelector(Cfg &cfg_, |
| BbNode &node_, |
| OpndVector &opnds_, |
| CompilationInterface &compilationInterface_) : |
| mm(cfg_.getMM()), |
| cfg(cfg_), |
| node(node_), |
| opnds(opnds_), |
| compilationInterface(compilationInterface_) { |
| |
| opndManager = cfg.getOpndManager(); |
| p0 = opndManager->getP0(); |
| } |
| |
| //----------------------------------------------------------------------------// |
| // InstructionCallback implementation |
| //----------------------------------------------------------------------------// |
| |
| //----------------------------------------------------------------------------// |
| // Add numeric values |
| |
| CG_OpndHandle *IpfInstCodeSelector::add(ArithmeticOp::Types opType, |
| CG_OpndHandle *src1, |
| CG_OpndHandle *src2) { |
| |
| IPF_LOG << " add; opType=" << opType << endl; |
| |
| Opnd *dst; |
| if (ipfConstantFolding && ((Opnd *)src1)->isImm() && ((Opnd *)src2)->isImm()) { |
| switch (opType) { |
| case ArithmeticOp::I4: |
| case ArithmeticOp::I: |
| dst = opndManager->newImm(IMM32(src1) + IMM32(src2)); break; |
| case ArithmeticOp::I8: |
| dst = opndManager->newImm(IMM64(src1) + IMM64(src2)); break; |
| default: |
| IPF_ASSERT(0); dst = NULL; break; |
| } |
| } else { |
| dst = opndManager->newRegOpnd(toOpndKind(opType), toDataKind(opType)); |
| add((RegOpnd *)dst, src1, src2); |
| } |
| return dst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Subtract numeric values |
| |
| CG_OpndHandle *IpfInstCodeSelector::sub(ArithmeticOp::Types opType, |
| CG_OpndHandle *src1, |
| CG_OpndHandle *src2) { |
| |
| IPF_LOG << " sub" << endl; |
| |
| Opnd *dst; |
| if (ipfConstantFolding && ((Opnd *)src1)->isImm() && ((Opnd *)src2)->isImm()) { |
| switch (opType) { |
| case ArithmeticOp::I4: |
| case ArithmeticOp::I: |
| dst = opndManager->newImm(IMM32(src1) - IMM32(src2)); break; |
| case ArithmeticOp::I8: |
| dst = opndManager->newImm(IMM64(src1) - IMM64(src2)); break; |
| default: |
| IPF_ASSERT(0); dst = NULL; break; |
| } |
| } else { |
| dst = opndManager->newRegOpnd(toOpndKind(opType), toDataKind(opType)); |
| sub((RegOpnd *)dst, src1, src2); |
| } |
| return dst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Multiply numeric values |
| |
| CG_OpndHandle *IpfInstCodeSelector::mul(ArithmeticOp::Types opType, |
| CG_OpndHandle *src1_, |
| CG_OpndHandle *src2_) { |
| |
| IPF_LOG << " mul" << endl; |
| |
| Opnd *dst; |
| if (ipfConstantFolding && ((Opnd *)src1_)->isImm() && ((Opnd *)src2_)->isImm()) { |
| // imm is always integer |
| switch (opType) { |
| case ArithmeticOp::I4: |
| case ArithmeticOp::I: |
| dst = opndManager->newImm(IMM32(src1_) * IMM32(src2_)); break; |
| case ArithmeticOp::I8: |
| dst = opndManager->newImm(IMM64(src1_) * IMM64(src2_)); break; |
| default: |
| IPF_ASSERT(0); dst = NULL; break; |
| } |
| } else { |
| RegOpnd *src1 = toRegOpnd(src1_); |
| RegOpnd *src2 = toRegOpnd(src2_); |
| RegOpnd *f0 = opndManager->getF0(); |
| |
| dst = opndManager->newRegOpnd(toOpndKind(opType), toDataKind(opType));; |
| if (dst->isFloating()) { |
| Completer cmplt = CMPLT_PC_DYNAMIC; |
| |
| switch (dst->getDataKind()) { |
| case DATA_D: cmplt = CMPLT_PC_DOUBLE; break; |
| case DATA_S: cmplt = CMPLT_PC_SINGLE; break; |
| default: IPF_ERR << "bad data kind for float mul\n"; break; |
| } |
| addNewInst(INST_FMA, cmplt, p0, dst, src1, src2, f0); |
| } else { |
| xma(INST_XMA_L, (RegOpnd *)dst, src1, src2); |
| } |
| } |
| return dst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Add integer to a reference |
| |
| CG_OpndHandle *IpfInstCodeSelector::addRef(RefArithmeticOp::Types opType, |
| CG_OpndHandle *refSrc, |
| CG_OpndHandle *intSrc) { |
| |
| IPF_LOG << " addRef" << endl; |
| IPF_ASSERT(((Opnd *)refSrc)->isReg()); |
| |
| RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, toDataKind(opType)); |
| add(dst, refSrc, intSrc); |
| return dst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Subtract integer from a reference |
| |
| CG_OpndHandle *IpfInstCodeSelector::subRef(RefArithmeticOp::Types opType, |
| CG_OpndHandle *refSrc, |
| CG_OpndHandle *intSrc) { |
| |
| IPF_LOG << " subRef" << endl; |
| IPF_ASSERT(((Opnd *)refSrc)->isReg()); |
| |
| RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, toDataKind(opType)); |
| sub(dst, refSrc, intSrc); |
| return dst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Subtract reference from reference |
| |
| CG_OpndHandle *IpfInstCodeSelector::diffRef(bool ovf, |
| CG_OpndHandle *src1, |
| CG_OpndHandle *src2) { |
| |
| IPF_LOG << " diffRef" << endl; |
| IPF_ASSERT(((Opnd *)src1)->isReg()); |
| IPF_ASSERT(((Opnd *)src2)->isReg()); |
| |
| RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, DATA_I64); |
| sub(dst, src1, src2); |
| return dst; |
| } |
| |
| |
| //----------------------------------------------------------------------------// |
| // Divide two numeric values |
| |
| CG_OpndHandle *IpfInstCodeSelector::tau_div(DivOp::Types opType, |
| CG_OpndHandle *src1, |
| CG_OpndHandle *src2, |
| CG_OpndHandle *tau_src1NonZero) { |
| |
| IPF_LOG << " tau_div" |
| << "; opType=" << opType |
| << ", src1=" << IrPrinter::toString((Opnd *)src1) |
| << ", src2=" << IrPrinter::toString((Opnd *)src2) |
| << endl; |
| |
| Opnd *dst = NULL; |
| if (ipfConstantFolding && ((Opnd *)src1)->isImm() && ((Opnd *)src2)->isImm() && IMM32(src2)!=0){ |
| // imm is always integer |
| switch (opType) { |
| case DivOp::I4: |
| dst = opndManager->newImm(IMM32(src1) / IMM32(src2)); break; |
| case DivOp::U4: |
| dst = opndManager->newImm(IMM32U(src1) / IMM32U(src2)); break; |
| case DivOp::I: |
| case DivOp::I8: |
| dst = opndManager->newImm(IMM64(src1) / IMM64(src2)); break; |
| case DivOp::U: |
| case DivOp::U8: |
| dst = opndManager->newImm(IMM64U(src1) / IMM64U(src2)); break; |
| default: |
| IPF_ASSERT(0); |
| dst = NULL; |
| } |
| } else { |
| dst = opndManager->newRegOpnd(toOpndKind(opType), toDataKind(opType)); |
| |
| switch (opType) { |
| case DivOp::I4: divInt((RegOpnd *)dst, toRegOpnd(src1), toRegOpnd(src2)); break; |
| case DivOp::I : |
| case DivOp::I8: divLong((RegOpnd *)dst, toRegOpnd(src1), toRegOpnd(src2)); break; |
| case DivOp::F : |
| case DivOp::D : divDouble((RegOpnd *)dst, src1, src2); break; |
| case DivOp::S : divFloat ((RegOpnd *)dst, src1, src2); break; |
| default : IPF_ERR << "unexpected type " << opType << endl; |
| } |
| } |
| return dst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Get remainder from the division of two numeric values |
| // On IPF computing integer remainder from division by zero does not result in hardware exception |
| |
| CG_OpndHandle *IpfInstCodeSelector::tau_rem(DivOp::Types opType, |
| CG_OpndHandle *src1, |
| CG_OpndHandle *src2, |
| CG_OpndHandle *tau_src2NonZero) { |
| |
| IPF_LOG << " tau_rem; opType=" << opType << endl; |
| |
| RegOpnd *dst = opndManager->newRegOpnd(toOpndKind(opType), toDataKind(opType)); |
| |
| if (dst->isFloating()) { |
| if (dst->getDataKind()==DATA_D) { |
| divDouble(dst, src1, src2, true); |
| } else { |
| divFloat(dst, src1, src2, true); |
| } |
| } else { |
| if (dst->getSize() > 4) { |
| divLong(dst, toRegOpnd(src1), toRegOpnd(src2), true); |
| } else { |
| divInt (dst, toRegOpnd(src1), toRegOpnd(src2), true); |
| } |
| } |
| |
| return dst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Negate numeric value |
| |
| CG_OpndHandle *IpfInstCodeSelector::neg(NegOp::Types opType, |
| CG_OpndHandle *src_) { |
| |
| IPF_LOG << " neg" << endl; |
| |
| Opnd *dst; |
| if (ipfConstantFolding && ((Opnd *)src_)->isImm()) { |
| switch (opType) { |
| case NegOp::I4: |
| dst = opndManager->newImm((I_32)0 - IMM32(src_)); break; |
| case NegOp::I: |
| case NegOp::I8: |
| dst = opndManager->newImm(0 - IMM64(src_)); break; |
| default: |
| IPF_ASSERT(0); |
| dst = NULL; |
| } |
| } else { |
| dst = opndManager->newRegOpnd(toOpndKind(opType), toDataKind(opType)); |
| RegOpnd *src = toRegOpnd(src_); |
| RegOpnd *r0 = opndManager->getR0(); |
| |
| if (dst->isFloating()) addNewInst(INST_FNEG, p0, dst, src); |
| else addNewInst(INST_SUB, p0, dst, r0, src); |
| } |
| return dst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Min |
| |
| CG_OpndHandle *IpfInstCodeSelector::min_op(NegOp::Types opType, |
| CG_OpndHandle *src1, |
| CG_OpndHandle *src2) { |
| |
| IPF_LOG << " min_op" << endl; |
| |
| Opnd *dst; |
| if (ipfConstantFolding && ((Opnd *)src1)->isImm() && ((Opnd *)src2)->isImm()) { |
| switch (opType) { |
| case NegOp::I4: |
| dst = opndManager->newImm(min(IMM32(src1), IMM32(src2))); break; |
| case NegOp::I: |
| case NegOp::I8: |
| dst = opndManager->newImm(min(IMM64(src1), IMM64(src2))); break; |
| default: |
| IPF_ASSERT(0); |
| dst = NULL; |
| } |
| } else { |
| dst = opndManager->newRegOpnd(toOpndKind(opType), toDataKind(opType)); |
| minMax((RegOpnd *)dst, src1, src2, false); |
| } |
| return dst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Max |
| |
| CG_OpndHandle *IpfInstCodeSelector::max_op(NegOp::Types opType, |
| CG_OpndHandle *src1, |
| CG_OpndHandle *src2) { |
| |
| IPF_LOG << " max_op" << endl; |
| |
| Opnd *dst; |
| if (ipfConstantFolding && ((Opnd *)src1)->isImm() && ((Opnd *)src2)->isImm()) { |
| switch (opType) { |
| case NegOp::I4: |
| dst = opndManager->newImm(max(IMM32(src1), IMM32(src2))); break; |
| case NegOp::I: |
| case NegOp::I8: |
| dst = opndManager->newImm(max(IMM64(src1), IMM64(src2))); break; |
| default: |
| IPF_ASSERT(0); |
| dst = NULL; |
| } |
| } else { |
| dst = opndManager->newRegOpnd(toOpndKind(opType), toDataKind(opType)); |
| minMax((RegOpnd *)dst, src1, src2, true); |
| } |
| return dst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Abs |
| |
| CG_OpndHandle *IpfInstCodeSelector::abs_op(NegOp::Types opType, |
| CG_OpndHandle *src_) { |
| Opnd *dst; |
| if (ipfConstantFolding && ((Opnd *)src_)->isImm()) { |
| switch (opType) { |
| case NegOp::I4: |
| dst = opndManager->newImm(abs(IMM32(src_))); break; |
| case NegOp::I: |
| case NegOp::I8: |
| dst = opndManager->newImm(labs(IMM64(src_))); break; |
| default: |
| IPF_ASSERT(0); |
| dst = NULL; |
| } |
| } else { |
| RegOpnd *src = toRegOpnd(src_); |
| dst = opndManager->newRegOpnd(toOpndKind(opType), toDataKind(opType)); |
| |
| if (dst->isFloating()) { |
| // TODO: check all the peculiarities of Math.min/max |
| addNewInst(INST_FABS, p0, dst, src); |
| } else { |
| // cmp.lt truePred, falsePred = src, 0 |
| // (truePred) dst = src |
| // (falsePred) dst = -src |
| RegOpnd *truePred = opndManager->newRegOpnd(OPND_P_REG, DATA_P); |
| RegOpnd *falsePred = opndManager->newRegOpnd(OPND_P_REG, DATA_P); |
| RegOpnd *r0 = opndManager->getR0(src); |
| |
| addNewInst(INST_DEF, p0, dst); |
| addNewInst(INST_DEF, p0, src); |
| |
| cmp(CMPLT_CMP_CREL_LT, truePred, falsePred, src, r0); |
| addNewInst(INST_MOV, truePred, dst, src); |
| addNewInst(INST_SUB, falsePred, dst, r0, src); |
| } |
| } |
| return dst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Logical and |
| |
| CG_OpndHandle *IpfInstCodeSelector::and_(IntegerOp::Types opType, |
| CG_OpndHandle *src1, |
| CG_OpndHandle *src2) { |
| |
| IPF_LOG << " and_ " << endl; |
| |
| Opnd *dst; |
| if (ipfConstantFolding && ((Opnd *)src1)->isImm() && ((Opnd *)src2)->isImm()) { |
| switch (opType) { |
| case IntegerOp::I4: |
| dst = opndManager->newImm(IMM32(src1) & IMM32(src2)); break; |
| case IntegerOp::I8: |
| dst = opndManager->newImm(IMM64(src1) & IMM64(src2)); break; |
| case IntegerOp::I : |
| dst = opndManager->newImm(IMM64U(src1) & IMM64U(src2)); break; |
| default: |
| IPF_ASSERT(0); |
| dst = NULL; |
| } |
| } else { |
| dst = opndManager->newRegOpnd(OPND_G_REG, toDataKind(opType)); |
| binOp(INST_AND, (RegOpnd *)dst, src1, src2); |
| } |
| return dst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Logical or |
| |
| CG_OpndHandle *IpfInstCodeSelector::or_(IntegerOp::Types opType, |
| CG_OpndHandle *src1, |
| CG_OpndHandle *src2) { |
| |
| IPF_LOG << " or_ " << endl; |
| |
| Opnd *dst; |
| if (ipfConstantFolding && ((Opnd *)src1)->isImm() && ((Opnd *)src2)->isImm()) { |
| switch (opType) { |
| case IntegerOp::I4: |
| dst = opndManager->newImm(IMM32(src1) | IMM32(src2)); break; |
| case IntegerOp::I8: |
| dst = opndManager->newImm(IMM64(src1) | IMM64(src2)); break; |
| case IntegerOp::I : |
| dst = opndManager->newImm(IMM64U(src1) | IMM64U(src2)); break; |
| default: |
| IPF_ASSERT(0); |
| dst = NULL; |
| } |
| } else { |
| dst = opndManager->newRegOpnd(OPND_G_REG, toDataKind(opType)); |
| binOp(INST_OR, (RegOpnd *)dst, src1, src2); |
| } |
| return dst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Logical xor |
| |
| CG_OpndHandle *IpfInstCodeSelector::xor_(IntegerOp::Types opType, |
| CG_OpndHandle *src1, |
| CG_OpndHandle *src2) { |
| |
| IPF_LOG << " xor_ " << endl; |
| |
| Opnd *dst; |
| if (ipfConstantFolding && ((Opnd *)src1)->isImm() && ((Opnd *)src2)->isImm()) { |
| switch (opType) { |
| case IntegerOp::I4: |
| dst = opndManager->newImm(IMM32(src1) ^ IMM32(src2)); break; |
| case IntegerOp::I8: |
| dst = opndManager->newImm(IMM64(src1) ^ IMM64(src2)); break; |
| case IntegerOp::I : |
| dst = opndManager->newImm(IMM64U(src1) ^ IMM64U(src2)); break; |
| default: |
| IPF_ASSERT(0); |
| dst = NULL; |
| } |
| } else { |
| dst = opndManager->newRegOpnd(OPND_G_REG, toDataKind(opType)); |
| binOp(INST_XOR, (RegOpnd *)dst, src1, src2); |
| } |
| return dst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Logical not |
| |
| CG_OpndHandle *IpfInstCodeSelector::not_(IntegerOp::Types opType, |
| CG_OpndHandle *src) { |
| |
| IPF_LOG << " not_ " << endl; |
| |
| Opnd *dst; |
| if (ipfConstantFolding && ((Opnd *)src)->isImm()) { |
| switch (opType) { |
| case IntegerOp::I4: |
| dst = opndManager->newImm(~IMM32(src)); break; |
| case IntegerOp::I8: |
| dst = opndManager->newImm(~IMM64(src)); break; |
| case IntegerOp::I : |
| dst = opndManager->newImm(~IMM64U(src)); break; |
| default: |
| IPF_ASSERT(0); |
| dst = NULL; |
| } |
| } else { |
| uint64 val = 0; |
| if (opType == IntegerOp::I4) val = 0xFFFFFFFF; |
| else val = 0xFFFFFFFFFFFFFFFFL; |
| |
| Opnd *allOnes = opndManager->newImm(val); |
| dst = opndManager->newRegOpnd(OPND_G_REG, toDataKind(opType)); |
| |
| binOp(INST_XOR, (RegOpnd *)dst, src, allOnes); |
| } |
| return dst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Shift left |
| |
| CG_OpndHandle *IpfInstCodeSelector::shl(IntegerOp::Types opType, |
| CG_OpndHandle *value, |
| CG_OpndHandle *shiftAmount) { |
| |
| IPF_LOG << " shl " << endl; |
| |
| if (ipfConstantFolding && ((Opnd *)value)->isImm() && ((Opnd *)shiftAmount)->isImm()) { |
| return opndManager->newImm(((Opnd *)value)->getValue() << ((Opnd *)shiftAmount)->getValue()); |
| } |
| |
| RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, toDataKind(opType)); |
| Opnd *shiftcount = (Opnd *)shiftAmount; |
| int bits = 5; |
| |
| switch (opType) { |
| case IntegerOp::I: |
| case IntegerOp::I4: bits = 5; break; |
| case IntegerOp::I8: bits = 6; break; |
| } |
| |
| shift(INST_SHL, dst, value, shiftcount, bits); |
| return dst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Shift right |
| |
| CG_OpndHandle *IpfInstCodeSelector::shr(IntegerOp::Types opType, |
| CG_OpndHandle *value, |
| CG_OpndHandle *shiftAmount) { |
| |
| IPF_LOG << " shr " << endl; |
| |
| if (ipfConstantFolding && ((Opnd *)value)->isImm() && ((Opnd *)shiftAmount)->isImm()) { |
| return opndManager->newImm(((Opnd *)value)->getValue() >> ((Opnd *)shiftAmount)->getValue()); |
| } |
| |
| RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, toDataKind(opType)); |
| int bits = 5; |
| |
| switch (opType) { |
| case IntegerOp::I: |
| case IntegerOp::I4: bits = 5; break; |
| case IntegerOp::I8: bits = 6; break; |
| } |
| |
| if (opType == IntegerOp::I4 && ((Opnd *)value)->getDataKind()==DATA_I32) { |
| sxt(value, 32); |
| } |
| shift(INST_SHR, dst, value, shiftAmount, bits); |
| return dst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Shift right unsigned |
| |
| CG_OpndHandle *IpfInstCodeSelector::shru(IntegerOp::Types opType, |
| CG_OpndHandle *value, |
| CG_OpndHandle *shiftAmount) { |
| |
| IPF_LOG << " shru " << endl; |
| |
| if (ipfConstantFolding && ((Opnd *)value)->isImm() && ((Opnd *)shiftAmount)->isImm()) { |
| if (opType==IntegerOp::I4) { |
| return opndManager->newImm((uint64)((U_32)((I_32)(((Opnd *)value)->getValue()))) >> ((Opnd *)shiftAmount)->getValue()); |
| } else { |
| return opndManager->newImm((uint64)(((Opnd *)value)->getValue()) >> ((Opnd *)shiftAmount)->getValue()); |
| } |
| } |
| |
| RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, toDataKind(opType)); |
| int bits = 5; |
| |
| switch (opType) { |
| case IntegerOp::I: |
| case IntegerOp::I4: bits = 5; break; |
| case IntegerOp::I8: bits = 6; break; |
| } |
| |
| if (opType == IntegerOp::I4 && ((Opnd *)value)->getDataKind()==DATA_I32) { |
| zxt(value, 32); |
| } |
| shift(INST_SHR_U, dst, value, shiftAmount, bits); |
| return dst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Shift left and add |
| |
| CG_OpndHandle *IpfInstCodeSelector::shladd(IntegerOp::Types opType, |
| CG_OpndHandle *value_, |
| U_32 imm, |
| CG_OpndHandle *addto_) { |
| |
| IPF_LOG << " shladd " << endl; |
| IPF_ASSERT(imm>=1 && imm<=4); |
| |
| if (ipfConstantFolding && ((Opnd *)value_)->isImm() && ((Opnd *)addto_)->isImm()) { |
| return opndManager->newImm((((Opnd *)value_)->getValue() << imm) + ((Opnd *)addto_)->getValue()); |
| } |
| |
| RegOpnd *value = toRegOpnd(value_); |
| RegOpnd *addto = toRegOpnd(addto_); |
| Opnd *count = opndManager->newImm(imm); |
| RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, toDataKind(opType)); |
| |
| sxt(value, dst->getSize()); |
| sxt(addto, dst->getSize()); |
| addNewInst(INST_SHLADD, p0, dst, value, count, addto); |
| return dst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Convert to integer |
| |
| CG_OpndHandle *IpfInstCodeSelector::convToInt(ConvertToIntOp::Types opType, |
| bool isSigned, |
| bool isZeroExtend, |
| ConvertToIntOp::OverflowMod ovfMod, |
| Type *dstType, |
| CG_OpndHandle *src_) { |
| |
| IPF_LOG << " convToInt " << IrPrinter::toString((Opnd *)src_); |
| IPF_LOG << " to " << Type::tag2str(dstType->tag); |
| IPF_LOG << "; isSigned=" << isSigned; |
| IPF_LOG << "; opType=" << opType << endl; |
| |
| if (ipfConstantFolding && ((Opnd *)src_)->isImm()) { |
| switch (opType) { |
| case ConvertToIntOp::I1: break; |
| case ConvertToIntOp::I2: break; |
| case ConvertToIntOp::I4: break; |
| default : return src_; |
| } |
| } |
| |
| RegOpnd *src = toRegOpnd(src_); |
| RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, toDataKind(dstType->tag)); |
| |
| if (src->isFloating()) { |
| // convert fp to int (signed saturating conversion) |
| if (dst->getSize() > 4) saturatingConv8(dst, src); |
| else saturatingConv4(dst, src); |
| } else { |
| // convert int to int |
| Completer cmplt = CMPLT_INVALID; |
| switch (opType) { |
| case ConvertToIntOp::I1: cmplt = CMPLT_XSZ_1; break; |
| case ConvertToIntOp::I2: cmplt = CMPLT_XSZ_2; break; |
| case ConvertToIntOp::I4: cmplt = CMPLT_XSZ_4; break; |
| default : break; |
| } |
| |
| InstCode instCode = dst->isSigned() |
| ? INST_SXT |
| : INST_ZXT; |
| if (cmplt == CMPLT_INVALID) addNewInst(INST_MOV, p0, dst, src); |
| else addNewInst(instCode, cmplt, p0, dst, src); |
| } |
| |
| return dst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Convert to floating-point |
| |
| CG_OpndHandle *IpfInstCodeSelector::convToFp(ConvertToFpOp::Types opType, |
| Type *dstType, |
| CG_OpndHandle *src_) { |
| |
| IPF_LOG << " convToFp" << endl; |
| |
| RegOpnd *src = toRegOpnd(src_); |
| DataKind srcDataKind = src->getDataKind(); |
| DataKind dstDataKind = toDataKind(dstType->tag); |
| |
| if (dstDataKind == srcDataKind) return src; |
| |
| RegOpnd *dst = opndManager->newRegOpnd(OPND_F_REG, dstDataKind); |
| |
| if (src->isFloating()) { |
| // convert from fp to fp |
| Completer cmplt = dstDataKind == DATA_D ? CMPLT_PC_DOUBLE : CMPLT_PC_SINGLE; |
| addNewInst(INST_FNORM, cmplt, p0, dst, src); |
| } else { |
| // convert from int to fp |
| bool isSigned = (opType != ConvertToFpOp::FloatFromUnsigned); |
| InstCode instCode = (isSigned ? INST_FCVT_XF : INST_FCVT_XUF); |
| sxt(src, 8); |
| addNewInst(INST_SETF_SIG, p0, dst, src); |
| addNewInst(instCode, p0, dst, dst); |
| } |
| |
| return dst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Load 32-bit integer constant |
| |
| CG_OpndHandle *IpfInstCodeSelector::ldc_i4(I_32 val) { |
| |
| IPF_LOG << " ldc_i4; val=" << val << endl; |
| |
| Opnd *dst; |
| if (ipfConstantFolding) { |
| dst = opndManager->newImm((int64)val); |
| } else { |
| dst = opndManager->newRegOpnd(OPND_G_REG, DATA_I32); |
| ldc((RegOpnd *)dst, (int64)val); |
| } |
| return dst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Load 64-bit integer constant |
| |
| CG_OpndHandle *IpfInstCodeSelector::ldc_i8(int64 val) { |
| |
| IPF_LOG << " ldc_i8; val=" << val << endl; |
| |
| Opnd *dst; |
| if (ipfConstantFolding) { |
| dst = opndManager->newImm(val); |
| } else { |
| dst = opndManager->newRegOpnd(OPND_G_REG, DATA_I64); |
| ldc((RegOpnd *)dst, val); |
| } |
| return dst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Load single FP constant |
| |
| CG_OpndHandle *IpfInstCodeSelector::ldc_s(float val) { |
| |
| IPF_LOG << " ldc_s; val=" << val << endl; |
| |
| if (val==0) { |
| return opndManager->getF0(); |
| } else if (val==1) { |
| return opndManager->getF1(); |
| } |
| |
| union { |
| float fr; |
| U_32 gr; |
| } tmpVal; |
| |
| tmpVal.fr = val; |
| |
| RegOpnd *dst = opndManager->newRegOpnd(OPND_F_REG, DATA_S); |
| Opnd *immOpnd = opndManager->newImm(tmpVal.gr); |
| RegOpnd *r3 = opndManager->newRegOpnd(OPND_G_REG, DATA_I64); |
| InstCode instCode = immOpnd->isFoldableImm(22) ? INST_MOV : INST_MOVL; |
| |
| addNewInst(instCode, p0, r3, immOpnd); |
| addNewInst(INST_SETF_S, p0, dst, r3); |
| |
| //FloatConstant *fc = new(mm) FloatConstant(val); |
| //ConstantRef *constref = opndManager->newConstantRef(fc); |
| //RegOpnd *r3 = opndManager->newRegOpnd(OPND_G_REG, DATA_I64); |
| //RegOpnd *dst = opndManager->newRegOpnd(OPND_F_REG, DATA_S); |
| // |
| //addNewInst(INST_MOVL, p0, r3, constref); |
| //addNewInst(INST_LDF, CMPLT_FSZ_S, p0, dst, r3); |
| |
| return dst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Load double FP constant |
| |
| CG_OpndHandle *IpfInstCodeSelector::ldc_d(double val) { |
| |
| IPF_LOG << " ldc_d; val=" << val << endl; |
| |
| if (val==0) { |
| return opndManager->getF0(); |
| } else if (val==1) { |
| return opndManager->getF1(); |
| } |
| |
| union { |
| double fr; |
| uint64 gr; |
| } tmpVal; |
| |
| tmpVal.fr = val; |
| |
| RegOpnd *dst = opndManager->newRegOpnd(OPND_F_REG, DATA_D); |
| Opnd *immOpnd = opndManager->newImm(tmpVal.gr); |
| RegOpnd *r3 = opndManager->newRegOpnd(OPND_G_REG, DATA_I64); |
| InstCode instCode = immOpnd->isFoldableImm(22) ? INST_MOV : INST_MOVL; |
| |
| addNewInst(instCode, p0, r3, immOpnd); |
| addNewInst(INST_SETF_D, p0, dst, r3); |
| |
| //DoubleConstant *fc = new(mm) DoubleConstant(val); |
| //ConstantRef *constref = opndManager->newConstantRef(fc); |
| //RegOpnd *r3 = opndManager->newRegOpnd(OPND_G_REG, DATA_I64); |
| //RegOpnd *dst = opndManager->newRegOpnd(OPND_F_REG, DATA_D); |
| // |
| //addNewInst(INST_MOVL, p0, r3, constref); |
| //addNewInst(INST_LDF, CMPLT_FSZ_D, p0, dst, r3); |
| |
| return dst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Load Null |
| |
| CG_OpndHandle *IpfInstCodeSelector::ldnull(bool compressed) { |
| |
| IPF_LOG << " ldnull; compressed=" << boolalpha << compressed << endl; |
| |
| if (false && ipfConstantFolding) { |
| if (opndManager->areRefsCompressed() == false) { |
| return opndManager->newImm(0); // return opndManager->getR0(); |
| } |
| |
| if (compressed) { |
| return opndManager->newImm(0); // return opndManager->getR0(); |
| } else { |
| return HEAPBASEIMM; // return HEAPBASE; |
| } |
| } else { |
| if (opndManager->areRefsCompressed() == false) { |
| return opndManager->getR0(); |
| } |
| |
| if (compressed) { |
| return opndManager->getR0(); |
| } else { |
| return HEAPBASE; |
| } |
| } |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Load variable |
| |
| CG_OpndHandle *IpfInstCodeSelector::ldVar(Type *dstType, U_32 varId) { |
| |
| IPF_LOG << " ldVar; dstType=" << Type::tag2str(dstType->tag) << ", varId=" << varId << endl; |
| |
| if (opnds[varId] == opndManager->getTau()) { |
| IPF_LOG << " tau operation - ignore" << endl; |
| return opndManager->getTau(); |
| } |
| |
| if (ipfConstantFolding && opnds[varId]->isImm()) { |
| return opnds[varId]; |
| } |
| |
| RegOpnd *src = toRegOpnd(opnds[varId]); |
| RegOpnd *dst = opndManager->newRegOpnd(toOpndKind(dstType->tag), toDataKind(dstType->tag)); |
| |
| sxt(src, dst->getSize()); |
| addNewInst(INST_MOV, p0, dst, src); |
| return dst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Store variable |
| |
| void IpfInstCodeSelector::stVar(CG_OpndHandle *_src, U_32 varId) { |
| |
| IPF_LOG << " stVar" |
| << "; varId=" << varId |
| << "; src=" << IrPrinter::toString((Opnd *)_src) |
| << endl; |
| |
| if (_src==opndManager->getTau() || opnds[varId]==opndManager->getTau()) { |
| IPF_LOG << " tau operation - ignore" << endl; |
| return; |
| } |
| |
| if (ipfConstantFolding && opnds[varId]->isImm() && ((Opnd *)_src)->isImm()) { |
| opnds[varId]->setValue(((Opnd *)_src)->getValue()); |
| } |
| |
| IPF_ASSERT(opnds[varId]->isReg()); |
| |
| Opnd *src = (Opnd *)_src; |
| if (src->isReg() || src->isImm(22)) { |
| addNewInst(INST_MOV, p0, opnds[varId], src); |
| } else { |
| addNewInst(INST_MOVL, p0, opnds[varId], src); |
| } |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Define an argument |
| |
| CG_OpndHandle *IpfInstCodeSelector::defArg(U_32 inArgPosition, Type *type) { |
| |
| |
| OpndKind opndKind = toOpndKind(type->tag); |
| DataKind dataKind = toDataKind(type->tag); |
| |
| Opnd *arg = opndManager->newInArg(opndKind, dataKind, inArgPosition); |
| IPF_LOG << " defArg " << IrPrinter::toString(arg) << " " << type->getName() << endl; |
| |
| if (arg->isFloating()) { |
| BbNode *prologNode = opndManager->getPrologNode(); |
| RegOpnd *newarg = opndManager->newRegOpnd(opndKind, dataKind); |
| Inst *inst = new(mm) Inst(mm, INST_MOV, p0, newarg, arg); |
| prologNode->addInst(inst); |
| arg = newarg; // it will be moved on preserved reg |
| |
| IPF_LOG << " " << IrPrinter::toString(inst) << endl; |
| } |
| |
| return arg; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Compare two values. Result is an integer. |
| |
| CG_OpndHandle *IpfInstCodeSelector::cmp(CompareOp::Operators cmpOp, |
| CompareOp::Types opType, |
| CG_OpndHandle *src1, |
| CG_OpndHandle *src2, |
| int ifNaNResult) { |
| |
| IPF_LOG << " cmp" |
| << "; opType=" << opType |
| << "; src1=" << IrPrinter::toString((Opnd *)src1) |
| << "; src2=" << IrPrinter::toString((Opnd *)src2) |
| << "\n"; |
| |
| InstCode instCode = toInstCmp(opType); |
| bool isFloating = (instCode == INST_FCMP); |
| Completer crel = toCmpltCrel(cmpOp, isFloating); |
| RegOpnd *truePred = opndManager->newRegOpnd(OPND_P_REG, DATA_P); |
| RegOpnd *falsePred = opndManager->newRegOpnd(OPND_P_REG, DATA_P); |
| RegOpnd *r0 = opndManager->getR0(); |
| RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, DATA_I32); |
| |
| addNewInst(INST_DEF, p0, dst); |
| |
| cmp(instCode, crel, truePred, falsePred, src1, src2); |
| addNewInst(INST_MOV, truePred, dst, opndManager->newImm(1)); |
| addNewInst(INST_MOV, falsePred, dst, r0); |
| |
| return dst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Check if operand is equal to zero. Result is integer. |
| |
| CG_OpndHandle *IpfInstCodeSelector::czero(CompareZeroOp::Types opType, |
| CG_OpndHandle *src) { |
| |
| IPF_LOG << " czero" |
| << "; src=" << IrPrinter::toString((Opnd *)src) |
| << endl; |
| |
| InstCode instCode = toInstCmp(opType); |
| Completer crel = CMPLT_CMP_CREL_EQ; |
| RegOpnd *truePred = opndManager->newRegOpnd(OPND_P_REG, DATA_P); |
| RegOpnd *falsePred = opndManager->newRegOpnd(OPND_P_REG, DATA_P); |
| RegOpnd *r0 = opndManager->getR0(); |
| RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, DATA_I32); |
| |
| addNewInst(INST_DEF, p0, dst); |
| |
| cmp(instCode, crel, truePred, falsePred, src, r0); |
| addNewInst(INST_MOV, truePred, dst, opndManager->newImm(1)); |
| addNewInst(INST_MOV, falsePred, dst, r0); |
| |
| return dst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Check if operand is not equal to zero. Result is integer. |
| |
| CG_OpndHandle *IpfInstCodeSelector::cnzero(CompareZeroOp::Types opType, |
| CG_OpndHandle *src) { |
| |
| IPF_LOG << " cnzero" |
| << "; src=" << IrPrinter::toString((Opnd *)src) |
| << endl; |
| |
| InstCode instCode = toInstCmp(opType); |
| Completer crel = CMPLT_CMP_CREL_NE; |
| RegOpnd *truePred = opndManager->newRegOpnd(OPND_P_REG, DATA_P); |
| RegOpnd *falsePred = opndManager->newRegOpnd(OPND_P_REG, DATA_P); |
| RegOpnd *r0 = opndManager->getR0(); |
| RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, DATA_I32); |
| |
| addNewInst(INST_DEF, p0, dst); |
| |
| cmp(instCode, crel, truePred, falsePred, src, r0); |
| addNewInst(INST_MOV, truePred, dst, opndManager->newImm(1)); |
| addNewInst(INST_MOV, falsePred, dst, r0); |
| |
| return dst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Copy operand |
| |
| CG_OpndHandle *IpfInstCodeSelector::copy(CG_OpndHandle *src_) { |
| |
| IPF_LOG << " copy" |
| << "; src_=" << IrPrinter::toString((Opnd *)src_) |
| << endl; |
| |
| if ((Opnd *)src_ == opndManager->getTau()) { |
| IPF_LOG << " tau operation - ignore" << endl; |
| return src_; |
| } |
| |
| RegOpnd *src = toRegOpnd(src_); |
| RegOpnd *dst = opndManager->newRegOpnd(src->getOpndKind(), src->getDataKind()); |
| |
| addNewInst(INST_MOV, p0, dst, src); |
| return dst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Statically cast object to type. |
| // This cast requires no runtime check. It's a compiler assertion. |
| |
| CG_OpndHandle *IpfInstCodeSelector::tau_staticCast(ObjectType *toType, |
| CG_OpndHandle *obj, |
| CG_OpndHandle *tauIsType) { |
| |
| IPF_LOG << " tau_staticCast" << endl; |
| |
| if (((Opnd *)obj)->isImm()) { |
| return obj; |
| } |
| |
| RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, toDataKind(toType->tag)); |
| |
| addNewInst(INST_MOV, p0, dst, obj); |
| return dst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Branch if result of cmp is true |
| |
| void IpfInstCodeSelector::branch(CompareOp::Operators cmpOp, |
| CompareOp::Types opType, |
| CG_OpndHandle *src1, |
| CG_OpndHandle *src2) { |
| |
| IPF_LOG << " branch" |
| << "; src1=" << IrPrinter::toString((Opnd *)src1) |
| << "; src2=" << IrPrinter::toString((Opnd *)src2) |
| << endl; |
| |
| if (false // TODO: need update cfg: branch edge target and "br" instruction target are different |
| && ipfConstantFolding && ((Opnd *)src1)->isImm() && ((Opnd *)src2)->isImm()) { |
| RegOpnd *truePred = opndManager->getP0(); |
| NodeRef *target = opndManager->newNodeRef(); |
| int64 v1 = ((Opnd *)src1)->getValue(), v2 = ((Opnd *)src2)->getValue(); |
| bool cmpres = false; |
| |
| switch (cmpOp) { |
| case CompareOp::Eq : cmpres = (v1 == v2); break; |
| case CompareOp::Ne : cmpres = (v1 != v2); break; |
| case CompareOp::Gt : cmpres = (v1 > v2); break; |
| case CompareOp::Gtu : cmpres = ((uint64)v1 > (uint64)v2); break; |
| case CompareOp::Ge : cmpres = (v1 >= v2); break; |
| case CompareOp::Geu : cmpres = ((uint64)v1 >= (uint64)v2); break; |
| default : IPF_ERR << "unexpected cmpOp type " << cmpOp << endl; |
| } |
| if (cmpres) { |
| addNewInst(INST_BR, CMPLT_BTYPE_COND, CMPLT_WH_SPTK, CMPLT_PH_MANY, truePred, target); |
| } |
| } else { |
| InstCode instCode = toInstCmp(opType); |
| bool isFloating = (instCode == INST_FCMP); |
| Completer crel = toCmpltCrel(cmpOp, isFloating); |
| RegOpnd *truePred = opndManager->newRegOpnd(OPND_P_REG, DATA_P); |
| NodeRef *target = opndManager->newNodeRef(); |
| |
| cmp(instCode, crel, truePred, p0, src1, src2); |
| addNewInst(INST_BR, CMPLT_BTYPE_COND, CMPLT_WH_DPTK, CMPLT_PH_MANY, truePred, target); |
| } |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Branch if src is zero |
| |
| void IpfInstCodeSelector::bzero(CompareZeroOp::Types opType, |
| CG_OpndHandle *src) { |
| |
| IPF_LOG << " bzero" |
| << "; src=" << IrPrinter::toString((Opnd *)src) |
| << endl; |
| IPF_ASSERT(((Opnd *)src)->isReg()); |
| |
| InstCode instCode = toInstCmp(opType); |
| RegOpnd *truePred = opndManager->newRegOpnd(OPND_P_REG, DATA_P); |
| NodeRef *target = opndManager->newNodeRef(); |
| RegOpnd *zero = NULL; |
| |
| if (opType==CompareZeroOp::Ref && opndManager->areRefsCompressed()) { |
| zero = HEAPBASE; // if refs are compressed - zero is HEAPBASE |
| } else { |
| zero = opndManager->getR0((RegOpnd *)src); // get "0" corresponding to src size/sign |
| } |
| |
| cmp(instCode, CMPLT_CMP_CREL_EQ, truePred, p0, src, zero); |
| addNewInst(INST_BR, CMPLT_BTYPE_COND, CMPLT_WH_DPTK, CMPLT_PH_MANY, truePred, target); |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Branch if src is not zero |
| |
| void IpfInstCodeSelector::bnzero(CompareZeroOp::Types opType, |
| CG_OpndHandle *src) { |
| |
| IPF_LOG << " bnzero" |
| << "; src=" << IrPrinter::toString((Opnd *)src) |
| << endl; |
| IPF_ASSERT(((Opnd *)src)->isReg()); |
| |
| InstCode instCode = toInstCmp(opType); |
| RegOpnd *truePred = opndManager->newRegOpnd(OPND_P_REG, DATA_P); |
| NodeRef *target = opndManager->newNodeRef(); |
| RegOpnd *zero = NULL; |
| |
| if (opType==CompareZeroOp::Ref && opndManager->areRefsCompressed()) { |
| zero = HEAPBASE; // if refs are compressed - zero is HEAPBASE |
| } else { |
| zero = opndManager->getR0((RegOpnd *)src); // get "0" corresponding to src size/sign |
| } |
| |
| cmp(instCode, CMPLT_CMP_CREL_NE, truePred, p0, src, zero); |
| addNewInst(INST_BR, CMPLT_BTYPE_COND, CMPLT_WH_DPTK, CMPLT_PH_MANY, truePred, target); |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Switch |
| // |
| // cmp.eq p8,p9 = r0, r0 // set p8 = true |
| // cmp.lt.unc p6,p7 = maxTgt, trg // if target is greater than |
| // // max target p6=true p7=false |
| // (p7) cmp.ne.and p8,p7 = fallThroughTgt, trg // if target is fall through target |
| // // p7=false p8=false |
| // (p6) mov tgt = defTgt // target is default target |
| // (p8) mov tgtAddr = switchTblAddr // load switch table address |
| // (p8) shladd r14 = trg, 3, tgtAddr // calculate switch table address |
| // // containing target address |
| // (p8) ld8 r14 = [r14] // load target address |
| // (p8) mov b1 = r14 // load target address to branch register |
| // (p8) br.cond.sptk b1 // branch to target |
| // // if p8 is false - fall through |
| |
| void IpfInstCodeSelector::tableSwitch(CG_OpndHandle *src, U_32 nTargets) { |
| |
| IPF_LOG << " tableSwitch" << endl; |
| |
| Constant *switchTable = new(mm) SwitchConstant(mm); |
| |
| Opnd *r0 = opndManager->getR0(); |
| Opnd *p6 = opndManager->newRegOpnd(OPND_P_REG, DATA_P); // default target is taken |
| Opnd *p7 = opndManager->newRegOpnd(OPND_P_REG, DATA_P); // check fall through target |
| Opnd *p8 = opndManager->newRegOpnd(OPND_P_REG, DATA_P); // fall through is not taken |
| Opnd *switchTblAddr = opndManager->newConstantRef(switchTable, DATA_SWITCH_REF); // switch table address |
| Opnd *tgtValue = (Opnd *)src; |
| Opnd *maxTgtValue = opndManager->newImm(nTargets-1); // max target value |
| Opnd *defTgtValue = opndManager->newImm(0); // default target value |
| Opnd *fallThroughTgtValue = opndManager->newImm(0); // FT target value |
| Opnd *tgt = opndManager->newRegOpnd(OPND_G_REG, DATA_I64); // target |
| Opnd *maxTgt = opndManager->newRegOpnd(OPND_G_REG, DATA_I64); // max target |
| Opnd *defTgt = opndManager->newRegOpnd(OPND_G_REG, DATA_I64); // default target |
| Opnd *fallThroughTgt = opndManager->newRegOpnd(OPND_G_REG, DATA_I64); // FT target |
| Opnd *shlCnt = opndManager->newImm(3); |
| Opnd *tgtAddr = opndManager->newRegOpnd(OPND_G_REG, DATA_I64); |
| Opnd *branchTgt = opndManager->newRegOpnd(OPND_B_REG, DATA_I64); |
| |
| addNewInst(INST_DEF, p0, tgt); |
| addNewInst(INST_DEF, p0, defTgt); |
| addNewInst(INST_DEF, p0, tgtAddr); |
| addNewInst(INST_DEF, p0, branchTgt); |
| |
| // mov to maxTgtValue, defTgtValue, fallThroughTgtValue to GRs |
| addNewInst(INST_MOV, p0, tgt, tgtValue); |
| addNewInst(INST_MOV, p0, maxTgt, maxTgtValue); |
| addNewInst(INST_MOV, p0, defTgt, defTgtValue); |
| addNewInst(INST_MOV, p0, fallThroughTgt, fallThroughTgtValue); |
| // just make 1 in p8 |
| addNewInst(INST_CMP4, CMPLT_CMP_CREL_EQ, p0, p8, p0, r0, r0); |
| // compare with default |
| addNewInst(INST_CMP4, CMPLT_CMP_CREL_GT, CMPLT_CMP_CTYPE_UNC, p0, p6, p7, tgt, maxTgt); |
| |
| Inst *tmpinst = new(mm) Inst(mm, INST_CMP4, CMPLT_CMP_CREL_LT, CMPLT_CMP_CTYPE_OR_ANDCM, p7, p6, p7, tgt, r0); |
| tmpinst->addOpnd(p6); |
| tmpinst->addOpnd(p7); |
| addInst(tmpinst); |
| |
| addNewInst(INST_MOV, p6, tgt, defTgt); |
| // compare if through target |
| addNewInst(INST_CMP4, CMPLT_CMP_CREL_NE, CMPLT_CMP_CTYPE_AND, p0, p8, p0, fallThroughTgt, tgt, p8); |
| // if not through target load tgt Address |
| addNewInst(INST_MOV, p8, tgtAddr, switchTblAddr); |
| addNewInst(INST_SHLADD, p8, tgtAddr, tgt, shlCnt, tgtAddr); |
| addNewInst(INST_LD, CMPLT_SZ_8, p8, tgtAddr, tgtAddr); |
| addNewInst(INST_MOV, p8, branchTgt, tgtAddr); |
| addNewInst(INST_SWITCH, p8, branchTgt, switchTblAddr, defTgtValue, fallThroughTgtValue); |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Direct call to the method |
| |
| CG_OpndHandle *IpfInstCodeSelector::call(U_32 numArgs, |
| CG_OpndHandle **args, |
| Type *retType, |
| MethodDesc *desc) { |
| |
| return tau_call(numArgs, args, retType, desc, NULL, NULL); |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Direct call to the method |
| |
| CG_OpndHandle *IpfInstCodeSelector::tau_call(U_32 numArgs, |
| CG_OpndHandle **args, |
| Type *retType, |
| MethodDesc *desc, |
| CG_OpndHandle *tauNullCheckedFirstArg, |
| CG_OpndHandle *tauTypesChecked) { |
| |
| IPF_LOG << " tau_call; method=" << desc->getName() |
| << ", desc=" << desc << ", addr=0x" << hex << *((uint64 *)desc->getIndirectAddress()) |
| << dec << endl; |
| |
| MethodRef *methodRef = opndManager->newMethodRef(desc); |
| RegOpnd *retOpnd = NULL; |
| |
| if(retType != NULL) { |
| retOpnd = opndManager->newRegOpnd(toOpndKind(retType->tag), toDataKind(retType->tag)); |
| } |
| |
| directCall(numArgs, (Opnd **)args, retOpnd, methodRef, p0); |
| |
| return retOpnd; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Indirect call |
| |
| CG_OpndHandle *IpfInstCodeSelector::tau_calli(U_32 numArgs, |
| CG_OpndHandle **args, |
| Type *retType, |
| CG_OpndHandle *methodPtr, |
| CG_OpndHandle *nonNullFirstArgTau, |
| CG_OpndHandle *tauTypesChecked) { |
| |
| IPF_LOG << " tau_calli; numArgs=" << numArgs |
| << ", retType=" << (retType ? Type::tag2str(retType->tag) : "NULL") << endl; |
| IPF_ASSERT(((Opnd *)methodPtr)->isReg()); |
| |
| RegOpnd *retOpnd = NULL; |
| if(retType != NULL) { |
| retOpnd = opndManager->newRegOpnd(toOpndKind(retType->tag), toDataKind(retType->tag)); |
| } |
| |
| indirectCall(numArgs, (Opnd **)args, retOpnd, (RegOpnd *)methodPtr, p0); |
| return retOpnd; |
| } |
| |
| //----------------------------------------------------------------------------// |
| |
| void IpfInstCodeSelector::ret() { |
| |
| IPF_LOG << " ret" << endl; |
| |
| RegOpnd *b0 = opndManager->getB0(); |
| addNewInst(INST_BR, CMPLT_BTYPE_RET, p0, b0); |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Return with a value |
| |
| void IpfInstCodeSelector::ret(CG_OpndHandle *retValue_) { |
| |
| IPF_LOG << " ret" << endl; |
| |
| RegOpnd *retValue = toRegOpnd(retValue_); |
| RegOpnd *b0 = opndManager->getB0(); |
| RegOpnd *retOpnd = NULL; |
| if(retValue->isFloating()) retOpnd = opndManager->newRegOpnd(OPND_F_REG, DATA_F, RET_F_REG); |
| else retOpnd = opndManager->newRegOpnd(OPND_G_REG, DATA_I64, RET_G_REG); |
| |
| addNewInst(INST_MOV, p0, retOpnd, retValue); |
| addNewInst(INST_BR, CMPLT_BTYPE_RET, p0, b0, retOpnd); |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Throw an exception |
| |
| void IpfInstCodeSelector::throwException(CG_OpndHandle *exceptionObj, bool createStackTrace) { |
| |
| IPF_LOG << " throwException; createStackTrace=" << createStackTrace << endl; |
| |
| Opnd *helperArgs[] = { (Opnd *)exceptionObj }; |
| |
| VM_RT_SUPPORT hId; |
| if (createStackTrace) hId = VM_RT_THROW_SET_STACK_TRACE; |
| else hId = VM_RT_THROW; |
| |
| uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); |
| Opnd *helperAddress = opndManager->newImm(address); |
| |
| directCall(1, helperArgs, NULL, helperAddress, p0); |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Throw system exception |
| |
| void IpfInstCodeSelector::throwSystemException(CompilationInterface::SystemExceptionId id) { |
| |
| IPF_LOG << " throwSystemException" << endl; |
| |
| //VM_RT_SUPPORT hId = VM_RT_UNKNOWN; |
| ObjectType* excType = NULL; |
| switch (id) { |
| case CompilationInterface::Exception_NullPointer: |
| excType = compilationInterface.findClassUsingBootstrapClassloader(NULL_POINTER_EXCEPTION); |
| //hId = VM_RT_NULL_PTR_EXCEPTION; |
| break; |
| case CompilationInterface::Exception_ArrayIndexOutOfBounds: |
| excType = compilationInterface.findClassUsingBootstrapClassloader(INDEX_OUT_OF_BOUNDS); |
| //hId = VM_RT_IDX_OUT_OF_BOUNDS; |
| break; |
| case CompilationInterface::Exception_ArrayTypeMismatch: |
| excType = compilationInterface.findClassUsingBootstrapClassloader(ARRAY_STORE_EXCEPTION); |
| //hId = VM_RT_ARRAY_STORE_EXCEPTION; |
| break; |
| case CompilationInterface::Exception_DivideByZero: |
| excType = compilationInterface.findClassUsingBootstrapClassloader(DIVIDE_BY_ZERO_EXCEPTION); |
| //hId = VM_RT_DIVIDE_BY_ZERO_EXCEPTION; |
| break; |
| default: |
| IPF_ERR << "unexpected id " << id << endl; |
| } |
| |
| throwException(excType); |
| } |
| |
| void IpfInstCodeSelector::throwException(ObjectType* excType) |
| { |
| assert(excType); |
| |
| Opnd *helperOpnds1[] = { |
| opndManager->newImm((int64) excType->getObjectSize()), |
| opndManager->newImm((int64) excType->getAllocationHandle()) |
| }; |
| |
| VM_RT_SUPPORT hId = VM_RT_NEW_RESOLVED_USING_VTABLE_AND_SIZE; |
| uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); |
| Opnd* helperAddress = opndManager->newImm(address); |
| OpndKind opndKind = toOpndKind(excType->tag); |
| DataKind dataKind = toDataKind(excType->tag); |
| RegOpnd* retOpnd = opndManager->newRegOpnd(opndKind, dataKind); |
| |
| directCall(2, helperOpnds1, retOpnd, helperAddress, p0); |
| |
| Opnd * helperOpnds2[] = { (Opnd*)retOpnd }; |
| MethodDesc* md = compilationInterface.resolveMethod( excType, |
| DEFAUlT_COSTRUCTOR_NAME, DEFAUlT_COSTRUCTOR_DESCRIPTOR); |
| call(1, (CG_OpndHandle **)helperOpnds2, NULL, md); |
| |
| Opnd * helperOpnds3[] = { (Opnd*)retOpnd }; |
| |
| hId = VM_RT_THROW; |
| address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); |
| helperAddress = opndManager->newImm(address); |
| |
| directCall(1, helperOpnds3, NULL, helperAddress, p0); |
| } |
| //----------------------------------------------------------------------------// |
| // Throw linking exception |
| |
| void IpfInstCodeSelector::throwLinkingException(Class_Handle encClass, |
| U_32 cp_ndx, |
| U_32 opcode) |
| { |
| |
| IPF_LOG << " throwLinkingException" << endl; |
| |
| Opnd *helperArgs[] = { |
| opndManager->newImm((int64) encClass), |
| opndManager->newImm(cp_ndx), |
| opndManager->newImm(opcode) |
| }; |
| |
| VM_RT_SUPPORT hId = VM_RT_THROW_LINKING_EXCEPTION; |
| uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); |
| Opnd *helperAddress = opndManager->newImm(address); |
| |
| directCall(3, helperArgs, NULL, helperAddress, p0); |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Copy exception object from r8 to new RegOpnd |
| |
| CG_OpndHandle *IpfInstCodeSelector::catchException(Type *exceptionType) { |
| |
| IPF_LOG << " catchException" << endl; |
| |
| RegOpnd *exceptionObj = opndManager->newRegOpnd(OPND_G_REG, DATA_U64, RET_G_REG); |
| RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, DATA_U64); |
| |
| addNewInst(INST_DEF, p0, exceptionObj); // DON'T REMOVE, THIS IS NOT FOR OPTIMIZATION |
| addNewInst(INST_MOV, p0, dst, exceptionObj); |
| return dst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Throw null pointer exception if base is NULL |
| |
| CG_OpndHandle *IpfInstCodeSelector::tau_checkNull(CG_OpndHandle *base, bool checksThisForInlinedMethod) { |
| |
| IPF_LOG << " tau_checkNull; base=" << IrPrinter::toString((Opnd *)base) << endl; |
| IPF_ASSERT(((Opnd *)base)->isReg()); |
| |
| RegOpnd *truePred = opndManager->newRegOpnd(OPND_P_REG, DATA_P); |
| RegOpnd *zero = NULL; |
| |
| if (opndManager->areRefsCompressed()) { |
| zero = HEAPBASE; |
| } else { |
| zero = opndManager->getR0((RegOpnd *)base); |
| } |
| |
| // p0 cmp.eq p2, p0 = base, zero |
| cmp(CMPLT_CMP_CREL_EQ, truePred, p0, base, zero); |
| |
| // p2 brl.call b0 = helperAddress |
| ObjectType* excType = compilationInterface.findClassUsingBootstrapClassloader(NULL_POINTER_EXCEPTION); |
| throwException(excType); |
| //VM_RT_SUPPORT hId = VM_RT_NULL_PTR_EXCEPTION; |
| //uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); |
| //Opnd *helperAddress = opndManager->newImm(address); |
| //directCall(0, NULL, NULL, helperAddress, truePred, CMPLT_WH_DPNT); |
| |
| return opndManager->getTau(); // return fake value (we do not use tau) |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Throw index out of range exception if index is larger than array length |
| |
| CG_OpndHandle *IpfInstCodeSelector::tau_checkBounds(CG_OpndHandle *arrayLen, |
| CG_OpndHandle *index) { |
| |
| IPF_LOG << " tau_checkBounds" << endl; |
| |
| // p0 cmp.ge p2, p0 = index, arrayLen |
| RegOpnd *truePred = opndManager->newRegOpnd(OPND_P_REG, DATA_P); |
| cmp(CMPLT_CMP_CREL_GE, truePred, p0, index, arrayLen); |
| |
| // p2 brl.call b0 = helperAddress |
| ObjectType* excType = compilationInterface.findClassUsingBootstrapClassloader(INDEX_OUT_OF_BOUNDS); |
| throwException(excType); |
| //VM_RT_SUPPORT hId = VM_RT_IDX_OUT_OF_BOUNDS; |
| //uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); |
| //Opnd *helperAddress = opndManager->newImm(address); |
| //directCall(0, NULL, NULL, helperAddress, truePred, CMPLT_WH_DPNT); |
| |
| return opndManager->getTau(); // return fake value (we do not use tau); |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Throw index out of range exception if (a > b) |
| |
| CG_OpndHandle *IpfInstCodeSelector::tau_checkLowerBound(CG_OpndHandle *a, |
| CG_OpndHandle *b) { |
| |
| IPF_LOG << " tau_checkLowerBound" << endl; |
| |
| // p0 cmp.gt p2, p0 = a, b |
| RegOpnd *truePred = opndManager->newRegOpnd(OPND_P_REG, DATA_P); |
| cmp(CMPLT_CMP_CREL_GT, truePred, p0, a, b); |
| |
| // p2 brl.call b0 = helperAddress |
| ObjectType* excType = compilationInterface.findClassUsingBootstrapClassloader(INDEX_OUT_OF_BOUNDS); |
| throwException(excType); |
| //VM_RT_SUPPORT hId = VM_RT_IDX_OUT_OF_BOUNDS; |
| //uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); |
| //Opnd *helperAddress = opndManager->newImm(address); |
| //directCall(0, NULL, NULL, helperAddress, truePred, CMPLT_WH_DPNT); |
| |
| return opndManager->getTau(); // return fake value (we do not use tau); |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Throw index out of range exception if (a >=u b) |
| |
| CG_OpndHandle *IpfInstCodeSelector::tau_checkUpperBound(CG_OpndHandle *a, |
| CG_OpndHandle *b) { |
| |
| IPF_LOG << " tau_checkUpperBound" << endl; |
| |
| // p0 cmp.ge p2, p0 = a, b |
| RegOpnd *truePred = opndManager->newRegOpnd(OPND_P_REG, DATA_P); |
| cmp(CMPLT_CMP_CREL_GEU, truePred, p0, a, b); |
| |
| // p2 brl.call b0 = helperAddress |
| ObjectType* excType = compilationInterface.findClassUsingBootstrapClassloader(INDEX_OUT_OF_BOUNDS); |
| throwException(excType); |
| //VM_RT_SUPPORT hId = VM_RT_IDX_OUT_OF_BOUNDS; |
| //uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); |
| //Opnd *helperAddress = opndManager->newImm(address); |
| //directCall(0, NULL, NULL, helperAddress, truePred, CMPLT_WH_DPNT); |
| |
| return opndManager->getTau(); // return fake value (we do not use tau); |
| } |
| |
| //----------------------------------------------------------------------------// |
| // p0 brl.call b0, Helper_IsValidElemType |
| // p0 mov retOpnd, r8 |
| // p0 cmp p3, p0 = retOpnd, r0 |
| // p3 brl.call b0, Helper_ElemTypeException |
| |
| CG_OpndHandle *IpfInstCodeSelector::tau_checkElemType(CG_OpndHandle *array, |
| CG_OpndHandle *src, |
| CG_OpndHandle *tauNullChecked, |
| CG_OpndHandle *tauIsArray) { |
| |
| IPF_LOG << " tau_checkElemType" << endl; |
| |
| Opnd *helperArgs[] = { |
| (Opnd *)src, |
| (Opnd *)array |
| }; |
| |
| // p0 brl.call b0, Helper_IsValidElemType |
| // p0 mov retOpnd, r8 |
| VM_RT_SUPPORT hId = VM_RT_AASTORE_TEST; |
| uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); |
| Opnd *helperAddress1 = opndManager->newImm(address); |
| RegOpnd *retOpnd = opndManager->newRegOpnd(OPND_G_REG, DATA_U64); |
| directCall(2, helperArgs, retOpnd, helperAddress1, p0); |
| |
| // p0 cmp p3, p0 = retOpnd, r0 |
| RegOpnd *r0 = opndManager->getR0(retOpnd); |
| RegOpnd *truePred = opndManager->newRegOpnd(OPND_P_REG, DATA_P); |
| cmp(CMPLT_CMP_CREL_EQ, truePred, p0, retOpnd, r0); |
| |
| // p3 brl.call b0, Helper_ElemTypeException |
| ObjectType* excType = compilationInterface.findClassUsingBootstrapClassloader(ARRAY_STORE_EXCEPTION); |
| throwException(excType); |
| //hId = VM_RT_ARRAY_STORE_EXCEPTION; |
| //address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); |
| //Opnd *helperAddress2 = opndManager->newImm(address); |
| //directCall(0, NULL, NULL, helperAddress2, truePred, CMPLT_WH_DPNT); |
| |
| return opndManager->getTau(); // return fake value (we do not use tau); |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Throw DivideByZeroException if checkZero's argument is 0 |
| |
| CG_OpndHandle *IpfInstCodeSelector::tau_checkZero(CG_OpndHandle *src_) { |
| |
| IPF_LOG << " tau_checkZero; src=" << IrPrinter::toString((Opnd *)src_) << endl; |
| |
| // p0 cmp.eq p2, p0 = base, r0 |
| RegOpnd *src = toRegOpnd(src_); |
| RegOpnd *r0 = opndManager->getR0(src); |
| RegOpnd *truePred = opndManager->newRegOpnd(OPND_P_REG, DATA_P); |
| cmp(CMPLT_CMP_CREL_EQ, truePred, p0, src, r0); |
| |
| // p2 brl.call b0 = helperAddress |
| ObjectType* excType = compilationInterface.findClassUsingBootstrapClassloader(DIVIDE_BY_ZERO_EXCEPTION); |
| throwException(excType); |
| //VM_RT_SUPPORT hId = VM_RT_DIVIDE_BY_ZERO_EXCEPTION; |
| //uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); |
| //Opnd *helperAddress = opndManager->newImm(address); |
| //directCall(0, NULL, NULL, helperAddress, truePred, CMPLT_WH_DPNT); |
| |
| return opndManager->getTau(); // return fake value (we do not use tau) |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Cast object to type and return the tau tied to this cast if casting is legal, |
| // otherwise throw an exception. |
| // checkCast is different from cast - checkCast returns the tau while cast returns |
| // the casted object (which is the same as the argument object) |
| |
| CG_OpndHandle *IpfInstCodeSelector::tau_checkCast(ObjectType *toType, |
| CG_OpndHandle *obj, |
| CG_OpndHandle *tauCheckedNull) { |
| |
| IPF_LOG << " tau_checkCast" << endl; |
| |
| Opnd *helperArgs[] = { |
| (Opnd *)obj, |
| (Opnd *)opndManager->newImm((uint64) toType->getRuntimeIdentifier()) |
| }; |
| |
| VM_RT_SUPPORT hId = VM_RT_CHECKCAST; |
| uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); |
| Opnd *helperAddress = opndManager->newImm(address); |
| directCall(2, helperArgs, NULL, helperAddress, p0); |
| |
| return opndManager->getTau(); // return fake value (we do not use tau) |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Store indirect |
| |
| void IpfInstCodeSelector::tau_stInd(CG_OpndHandle *src_, |
| CG_OpndHandle *ptr_, |
| Type::Tag memType, |
| bool autoCompressRef, |
| CG_OpndHandle *tauBaseNonNull, |
| CG_OpndHandle *tauAddressInRange, |
| CG_OpndHandle *tauElemTypeChecked) { |
| |
| IPF_LOG << " tau_stInd" << endl; |
| |
| DataKind dataKind = toDataKind(memType); |
| InstCode instCode = IpfType::isFloating(dataKind) ? INST_STF : INST_ST; |
| Completer cmplt = toCmpltSz(dataKind); |
| RegOpnd *src = toRegOpnd(src_); |
| RegOpnd *ptr = toRegOpnd(ptr_); |
| |
| if (autoCompressRef) { |
| IPF_ASSERT(opndManager->areRefsCompressed()); |
| dataKind = DATA_U32; |
| cmplt = toCmpltSz(dataKind); |
| RegOpnd *tmp = opndManager->newRegOpnd(OPND_G_REG, dataKind); |
| sub(tmp, src, HEAPBASE); |
| |
| addNewInst(instCode, cmplt, p0, ptr, tmp); |
| } else { |
| addNewInst(instCode, cmplt, p0, ptr, src); |
| } |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Load indirect |
| |
| CG_OpndHandle *IpfInstCodeSelector::tau_ldInd(Type *dstType, |
| CG_OpndHandle *ptr_, |
| Type::Tag memType, |
| bool autoUncompressRef, |
| bool speculateLoad, |
| CG_OpndHandle *tauBaseNonNull, |
| CG_OpndHandle *tauAddressInRange) { |
| |
| IPF_LOG << " tau_ldInd;" |
| << " dstType=" << Type::tag2str(dstType->tag) |
| << ", memType=" << Type::tag2str(memType) |
| << ", autoUncompressRef=" << autoUncompressRef << endl; |
| |
| DataKind dataKind = toDataKind(memType); |
| InstCode instCode = IpfType::isFloating(dataKind) ? INST_LDF : INST_LD; |
| Completer cmplt = toCmpltSz(dataKind); |
| RegOpnd *ptr = toRegOpnd(ptr_); |
| RegOpnd *dst = opndManager->newRegOpnd(toOpndKind(dstType->tag), toDataKind(dstType->tag)); |
| |
| if (autoUncompressRef) { |
| IPF_ASSERT(opndManager->areRefsCompressed()); |
| cmplt = toCmpltSz(DATA_U32); |
| addNewInst(instCode, cmplt, p0, dst, ptr); |
| add(dst, dst, HEAPBASE); |
| } else { |
| addNewInst(instCode, cmplt, p0, dst, ptr); |
| sxt(dst, 8, cmplt); |
| } |
| |
| return dst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Load string |
| |
| CG_OpndHandle *IpfInstCodeSelector::ldString(MethodDesc *enclosingMethod, |
| U_32 stringToken, |
| bool uncompress) { |
| |
| IPF_LOG << " ldString" << endl; |
| |
| Opnd *helperArgs[] = { |
| opndManager->newImm(stringToken), |
| opndManager->newImm((int64) enclosingMethod->getParentType()->getRuntimeIdentifier()) |
| }; |
| |
| RegOpnd *retOpnd = opndManager->newRegOpnd(OPND_G_REG, DATA_BASE); |
| VM_RT_SUPPORT hId = VM_RT_LDC_STRING; |
| uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); |
| Opnd *helperAddress = opndManager->newImm(address); |
| |
| directCall(2, helperArgs, retOpnd, helperAddress, p0); |
| return retOpnd; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Load address of the object lock |
| // (aka lock owner field in the synchronization header) |
| |
| CG_OpndHandle *IpfInstCodeSelector::ldLockAddr(CG_OpndHandle *obj) { |
| |
| IPF_LOG << " ldLockAddr(" << IrPrinter::toString((Opnd *)obj) << ")" << endl; |
| |
| RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, DATA_MPTR); |
| Opnd *offset = opndManager->newImm(LOC_OFFSET); |
| |
| add(dst, offset, obj); |
| return dst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Load address of the virtual/interface table slot that contains function address |
| |
| CG_OpndHandle *IpfInstCodeSelector::tau_ldVirtFunAddr(Type *dstType, |
| CG_OpndHandle *vtableAddr, |
| MethodDesc *methodDesc, |
| CG_OpndHandle *tauVtableHasDesc) { |
| |
| IPF_LOG << " tau_ldVirtFunAddr; dstType==" << Type::tag2str(dstType->tag) |
| << ", method=" << methodDesc->getName() << endl; |
| IPF_ASSERT(((Opnd *)vtableAddr)->isReg()); |
| |
| uint64 offsetVal = methodDesc->getOffset(); // get method offset in class VTable |
| Opnd *offset = opndManager->newImm(offsetVal); |
| RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, DATA_U64); |
| |
| add(dst, offset, vtableAddr); |
| addNewInst(INST_LD, CMPLT_SZ_8, p0, dst, dst); |
| return dst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Load virtual table address |
| |
| CG_OpndHandle *IpfInstCodeSelector::tau_ldVTableAddr(Type *dstType, |
| CG_OpndHandle *base, |
| CG_OpndHandle *tauBaseNonNull) { |
| |
| IPF_LOG << " tau_ldVTableAddr; dstType==" << Type::tag2str(dstType->tag) << endl; |
| IPF_ASSERT(((Opnd *)base)->isReg()); |
| |
| Opnd *offset = opndManager->getVtableOffset(); |
| RegOpnd *vtable = opndManager->newRegOpnd(OPND_G_REG, toDataKind(dstType->tag)); |
| RegOpnd *addr = NULL; |
| |
| if(offset == NULL) { // if VTable has offset 0 - base represents VTable address |
| addr = (RegOpnd *)base; |
| } else { |
| addr = opndManager->newRegOpnd(OPND_G_REG, toDataKind(dstType->tag)); |
| add(addr, offset, base); |
| } |
| |
| Completer completer = CMPLT_INVALID; |
| if(opndManager->areVtablePtrsCompressed()) completer = CMPLT_SZ_4; |
| else completer = CMPLT_SZ_8; |
| |
| addNewInst(INST_LD, completer, p0, vtable, addr); |
| |
| if (dstType->tag==Type::VTablePtr && opndManager->areVtablePtrsCompressed()) { |
| add(vtable, vtable, VTABLEBASE); |
| } |
| |
| return vtable; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // get vtable constant (a constant pointer) |
| |
| CG_OpndHandle *IpfInstCodeSelector::getVTableAddr(Type *dstType, |
| ObjectType *base) { |
| |
| uint64 value = (uint64) base->getVTable(); |
| // if (dstType->tag==Type::VTablePtr && opndManager->areVtablePtrsCompressed()) { |
| // value += (uint64) compilationInterface.getVTableBase(); |
| // } |
| |
| Opnd *addr = opndManager->newImm(value); |
| IPF_LOG << " getVTableAddr" << endl << " addr " << IrPrinter::toString(addr) << endl; |
| |
| return addr; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // get java.langObject |
| |
| CG_OpndHandle *IpfInstCodeSelector::getClassObj(Type *dstType, |
| ObjectType *base) { |
| |
| IPF_LOG << " getClassObj" << endl; |
| |
| uint64 typeRuntimeId = (uint64) base->getRuntimeIdentifier(); |
| Opnd *helperArgs1[] = { opndManager->newImm(typeRuntimeId) }; |
| |
| VM_RT_SUPPORT hId1 = VM_RT_CLASS_2_JLC; |
| uint64 address1 = (uint64) compilationInterface.getRuntimeHelperAddress(hId1); |
| Opnd* helperAddress1 = opndManager->newImm(address1); |
| OpndKind opndKind = toOpndKind(dstType->tag); |
| DataKind dataKind = toDataKind(dstType->tag); |
| RegOpnd* retOpnd = opndManager->newRegOpnd(opndKind, dataKind); |
| |
| directCall(1, helperArgs1, retOpnd, helperAddress1, p0); |
| return retOpnd; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Load interface table address |
| |
| CG_OpndHandle *IpfInstCodeSelector::tau_ldIntfTableAddr(Type *dstType, |
| CG_OpndHandle *base, |
| NamedType *vtableType) { |
| |
| IPF_LOG << " tau_ldIntfTableAddr; dstType==" << Type::tag2str(dstType->tag) |
| << "; vtableType=" << Type::tag2str(vtableType->tag) << endl; |
| |
| Opnd *helperArgs[] = { |
| (Opnd *)base, |
| (Opnd *)opndManager->newImm((uint64) vtableType->getRuntimeIdentifier()) |
| }; |
| |
| VM_RT_SUPPORT hId = VM_RT_GET_INTERFACE_VTABLE_VER0; |
| uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); |
| Opnd *helperAddress = opndManager->newImm(address); |
| RegOpnd *retOpnd = opndManager->newRegOpnd(toOpndKind(dstType->tag), toDataKind(dstType->tag)); |
| |
| directCall(2, helperArgs, retOpnd, helperAddress, p0); |
| return retOpnd; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Load address of the field at "base + offset" |
| |
| CG_OpndHandle *IpfInstCodeSelector::ldFieldAddr(Type *fieldRefType, |
| CG_OpndHandle *base, |
| FieldDesc *fieldDesc) { |
| |
| IPF_LOG << " ldFieldAddr " << fieldDesc->getName() |
| << "(" << Type::tag2str(fieldRefType->tag) << ")" |
| << "; base=" << IrPrinter::toString((Opnd *)base) |
| << endl; |
| |
| Opnd *fieldOffset = opndManager->newImm(fieldDesc->getOffset()); |
| RegOpnd *fieldAddress = opndManager->newRegOpnd(OPND_G_REG, DATA_MPTR); |
| |
| add(fieldAddress, fieldOffset, base); |
| return fieldAddress; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Load static field address |
| |
| CG_OpndHandle *IpfInstCodeSelector::ldStaticAddr(Type *fieldRefType, FieldDesc *fieldDesc) { |
| |
| IPF_LOG << " ldStaticAddr " << fieldDesc->getName() |
| << "(" << Type::tag2str(fieldRefType->tag) << ")"; |
| |
| Opnd *dst = opndManager->newImm((uint64) fieldDesc->getAddress()); |
| IPF_LOG << " addr is " << IrPrinter::toString(dst) << endl; |
| return dst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Check if an object has given type. |
| // If it is return 1 else return 0. |
| |
| CG_OpndHandle *IpfInstCodeSelector::tau_instanceOf(ObjectType *type, |
| CG_OpndHandle *obj, |
| CG_OpndHandle *tauCheckedNull) { |
| IPF_LOG << " tau_instanceOf" << endl; |
| |
| Opnd *helperArgs[] = { |
| (Opnd *)obj, |
| opndManager->newImm((uint64) type->getRuntimeIdentifier()) |
| }; |
| |
| VM_RT_SUPPORT hId = VM_RT_INSTANCEOF; |
| uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); |
| Opnd *helperAddress = opndManager->newImm(address); |
| RegOpnd *retOpnd = opndManager->newRegOpnd(OPND_G_REG, DATA_I32); |
| |
| directCall(2, helperArgs, retOpnd, helperAddress, p0); |
| return retOpnd; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Initialize type |
| |
| void IpfInstCodeSelector::initType(Type *type) { |
| |
| IPF_LOG << " initType" << endl; |
| IPF_ASSERT(type->isObject()); |
| |
| uint64 typeRuntimeId = (uint64) type->asNamedType()->getRuntimeIdentifier(); |
| Opnd *helperArgs[] = { opndManager->newImm(typeRuntimeId) }; |
| |
| VM_RT_SUPPORT hId = VM_RT_INITIALIZE_CLASS; |
| uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); |
| Opnd *helperAddress = opndManager->newImm(address); |
| |
| directCall(1, helperArgs, NULL, helperAddress, p0); |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Create new object |
| |
| CG_OpndHandle *IpfInstCodeSelector::newObj(ObjectType *objType) { |
| |
| IPF_LOG << " newObj" << endl; |
| |
| Opnd *helperArgs[] = { |
| opndManager->newImm((int64) objType->getObjectSize()), |
| opndManager->newImm((int64) objType->getAllocationHandle()) |
| }; |
| |
| VM_RT_SUPPORT hId = VM_RT_NEW_RESOLVED_USING_VTABLE_AND_SIZE; |
| uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); |
| Opnd *helperAddress = opndManager->newImm(address); |
| OpndKind opndKind = toOpndKind(objType->tag); |
| DataKind dataKind = toDataKind(objType->tag); |
| RegOpnd *retOpnd = opndManager->newRegOpnd(opndKind, dataKind); |
| |
| directCall(2, helperArgs, retOpnd, helperAddress, p0); |
| return retOpnd; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Create new array |
| |
| CG_OpndHandle *IpfInstCodeSelector::newArray(ArrayType *arrayType, |
| CG_OpndHandle *numElems) { |
| |
| IPF_LOG << " newArray of " << arrayType->getElementType()->getName() << endl; |
| |
| Opnd *helperArgs[] = { |
| (Opnd *)numElems, |
| opndManager->newImm((int64) arrayType->getAllocationHandle()) |
| }; |
| |
| VM_RT_SUPPORT hId = VM_RT_NEW_VECTOR_USING_VTABLE; |
| uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); |
| Opnd *helperAddress = opndManager->newImm(address); |
| RegOpnd *retOpnd = opndManager->newRegOpnd(OPND_G_REG, DATA_BASE); |
| |
| directCall(2, helperArgs, retOpnd, helperAddress, p0); |
| return retOpnd; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Create multi-dimensional new array |
| |
| CG_OpndHandle *IpfInstCodeSelector::newMultiArray(ArrayType *arrayType, |
| U_32 numDims, |
| CG_OpndHandle **dims) { |
| |
| Opnd *helperArgs[2 + numDims]; |
| |
| helperArgs[0] = opndManager->newImm((uint64)arrayType->getRuntimeIdentifier()); |
| helperArgs[1] = opndManager->newImm(numDims); |
| for (U_32 i = 0; i < numDims; i++) { |
| helperArgs[i + 2] = (Opnd *)dims[numDims - 1 - i]; |
| } |
| |
| VM_RT_SUPPORT hId = VM_RT_MULTIANEWARRAY_RESOLVED; |
| uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); |
| Opnd *helperAddress = opndManager->newImm(address); |
| RegOpnd *retOpnd = opndManager->newRegOpnd(OPND_G_REG, DATA_BASE); |
| |
| directCall(2 + numDims, helperArgs, retOpnd, helperAddress, p0); |
| return retOpnd; |
| } |
| //----------------------------------------------------------------------------// |
| // Compute address of the first array element |
| |
| CG_OpndHandle *IpfInstCodeSelector::ldElemBaseAddr(CG_OpndHandle *array) { |
| |
| IPF_LOG << " ldElemBaseAddr " << endl; |
| |
| Opnd *offset = opndManager->newImm(opndManager->getElemBaseOffset()); |
| RegOpnd *elemBase = opndManager->newRegOpnd(OPND_G_REG, DATA_MPTR); |
| add(elemBase, offset, array); |
| |
| return elemBase; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Compute address of the array element given |
| // address of the first element and index |
| |
| CG_OpndHandle *IpfInstCodeSelector::addElemIndex(Type *elemType, |
| CG_OpndHandle *elemBase_, |
| CG_OpndHandle *index_) { |
| |
| IPF_LOG << " addElemIndex; type=" << Type::tag2str(elemType->tag) << endl; |
| |
| RegOpnd *elemBase = toRegOpnd(elemBase_); |
| RegOpnd *index = toRegOpnd(index_); |
| RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, DATA_U64); |
| int16 elemSize = IpfType::getSize(toDataKind(elemType->tag)); |
| int16 countVal = 0; |
| |
| switch(elemSize) { |
| case 1 : countVal = -1; break; |
| case 2 : countVal = 1; break; |
| case 4 : countVal = 2; break; |
| case 8 : countVal = 3; break; |
| case 16 : countVal = 0; break; |
| default : IPF_ERR << "elemSize =" << elemSize << endl; |
| } |
| |
| if(countVal >= 0) { |
| Opnd *count = opndManager->newImm(countVal); |
| addNewInst(INST_SHLADD, p0, dst, index, count, elemBase); |
| } else { |
| addNewInst(INST_ADD, p0, dst, index, elemBase); |
| } |
| |
| return dst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Load array length |
| |
| CG_OpndHandle *IpfInstCodeSelector::tau_arrayLen(Type *dstType, |
| ArrayType *arrayType, |
| Type *lenType, |
| CG_OpndHandle *base, |
| CG_OpndHandle *tauArrayNonNull, |
| CG_OpndHandle *tauIsArray) { |
| |
| IPF_LOG << " tau_arrayLen" << endl; |
| |
| uint64 offset = arrayType->getArrayLengthOffset(); |
| Opnd *offsetOpnd = opndManager->newImm(offset); |
| RegOpnd *addr = opndManager->newRegOpnd(OPND_G_REG, DATA_MPTR); |
| add(addr, offsetOpnd, base); |
| |
| return tau_ldInd(dstType, addr, lenType->tag, false, false, NULL, NULL); |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Acquire monitor for an object |
| |
| void IpfInstCodeSelector::tau_monitorEnter(CG_OpndHandle *obj, |
| CG_OpndHandle *tauIsNonNull) { |
| |
| IPF_LOG << " tau_monitorEnter" << endl; |
| |
| Opnd *helperArgs[] = { (Opnd *)obj }; |
| |
| VM_RT_SUPPORT hId = VM_RT_MONITOR_ENTER; |
| uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); |
| Opnd *helperAddress = opndManager->newImm(address); |
| |
| directCall(1, helperArgs, NULL, helperAddress, p0); |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Release monitor for an object |
| |
| void IpfInstCodeSelector::tau_monitorExit(CG_OpndHandle *obj, |
| CG_OpndHandle *tauIsNonNull) { |
| |
| IPF_LOG << " tau_monitorExit" << endl; |
| |
| Opnd *helperArgs[] = { (Opnd *)obj }; |
| |
| VM_RT_SUPPORT hId = VM_RT_MONITOR_EXIT; |
| uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); |
| Opnd *helperAddress = opndManager->newImm(address); |
| |
| directCall(1, helperArgs, NULL, helperAddress, p0); |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Acquire monitor for a class |
| |
| void IpfInstCodeSelector::typeMonitorEnter(NamedType *type) { |
| |
| IPF_LOG << " typeMonitorEnter" << endl; |
| |
| uint64 typeRuntimeId = (uint64) type->getRuntimeIdentifier(); |
| Opnd *helperArgs1[] = { opndManager->newImm(typeRuntimeId) }; |
| |
| VM_RT_SUPPORT hId1 = VM_RT_CLASS_2_JLC; |
| uint64 address1 = (uint64) compilationInterface.getRuntimeHelperAddress(hId1); |
| Opnd* helperAddress1 = opndManager->newImm(address1); |
| OpndKind opndKind = toOpndKind(type->tag); |
| DataKind dataKind = toDataKind(type->tag); |
| RegOpnd* retOpnd = opndManager->newRegOpnd(opndKind, dataKind); |
| |
| directCall(1, helperArgs1, retOpnd, helperAddress1, p0); |
| |
| Opnd *helperArgs2[] = { retOpnd }; |
| |
| VM_RT_SUPPORT hId2 = VM_RT_MONITOR_ENTER; |
| uint64 address2 = (uint64) compilationInterface.getRuntimeHelperAddress(hId2); |
| Opnd* helperAddress2 = opndManager->newImm(address2); |
| |
| directCall(1, helperArgs2, NULL, helperAddress2, p0); |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Release monitor for a class |
| |
| void IpfInstCodeSelector::typeMonitorExit(NamedType *type) { |
| |
| IPF_LOG << " typeMonitorExit" << endl; |
| |
| uint64 typeRuntimeId = (uint64) type->getRuntimeIdentifier(); |
| Opnd *helperArgs1[] = { opndManager->newImm(typeRuntimeId) }; |
| |
| VM_RT_SUPPORT hId1 = VM_RT_CLASS_2_JLC; |
| uint64 address1 = (uint64) compilationInterface.getRuntimeHelperAddress(hId1); |
| Opnd* helperAddress1 = opndManager->newImm(address1); |
| OpndKind opndKind = toOpndKind(type->tag); |
| DataKind dataKind = toDataKind(type->tag); |
| RegOpnd* retOpnd = opndManager->newRegOpnd(opndKind, dataKind); |
| |
| directCall(1, helperArgs1, retOpnd, helperAddress1, p0); |
| |
| Opnd *helperArgs2[] = { retOpnd }; |
| |
| VM_RT_SUPPORT hId2 = VM_RT_MONITOR_EXIT; |
| uint64 address2 = (uint64) compilationInterface.getRuntimeHelperAddress(hId2); |
| Opnd* helperAddress2 = opndManager->newImm(address2); |
| |
| directCall(1, helperArgs2, NULL, helperAddress2, p0); |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Wrapper around balanced monitor enter. Set cmpxchg role to BalancedMonitorEnter |
| |
| CG_OpndHandle *IpfInstCodeSelector::tau_balancedMonitorEnter(CG_OpndHandle *obj, |
| CG_OpndHandle *lockAddr, |
| CG_OpndHandle *tauIsNonNull) { |
| IPF_LOG << " tau_balancedMonitorEnter" << endl; |
| |
| tau_monitorEnter(obj, tauIsNonNull); |
| return opndManager->getR0(); |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Balanced monitor exit |
| |
| void IpfInstCodeSelector::balancedMonitorExit(CG_OpndHandle *obj, |
| CG_OpndHandle *lockAddr, |
| CG_OpndHandle *oldLock) { |
| IPF_LOG << " balancedMonitorExit" << endl; |
| |
| tau_monitorExit(obj, NULL); |
| } |
| |
| //----------------------------------------------------------------------------// |
| // CG helper protected methods |
| //----------------------------------------------------------------------------// |
| |
| //----------------------------------------------------------------------------// |
| // Create direct call to the method |
| |
| void IpfInstCodeSelector::directCall(U_32 numArgs, |
| Opnd **args, |
| RegOpnd *retOpnd, |
| Opnd *methodAddress, |
| RegOpnd *pred, |
| Completer whetherHint) { |
| |
| RegOpnd *b0 = opndManager->getB0(); |
| RegOpnd *convOpnd = makeConvOpnd(retOpnd); |
| Inst *callInst = new(mm) Inst(mm, INST_BRL13, CMPLT_BTYPE_CALL, whetherHint, CMPLT_PH_MANY |
| , pred, convOpnd, b0, methodAddress); |
| |
| opndManager->setContainCall(true); // set flag OpndManager::containCall |
| makeCallArgs(numArgs, args, callInst, pred); // add instructions moving args in appropriate locations |
| |
| addInst(callInst); // add "call" inst |
| makeRetVal(retOpnd, convOpnd, pred); // add instruction moving ret value from r8/f8 |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Create indirect call to the method |
| |
| void IpfInstCodeSelector::indirectCall(U_32 numArgs, |
| Opnd **args, |
| RegOpnd *retOpnd, |
| RegOpnd *methodPtr, |
| RegOpnd *pred, |
| Completer whetherHint) { |
| |
| RegOpnd *b0 = opndManager->getB0(); |
| RegOpnd *convOpnd = makeConvOpnd(retOpnd); |
| RegOpnd *callTgt = opndManager->newRegOpnd(OPND_B_REG, DATA_U64); |
| Inst *ldAddress = new(mm) Inst(mm, INST_MOV, pred, callTgt, methodPtr); |
| Inst *callInst = new(mm) Inst(mm, INST_BR13, CMPLT_BTYPE_CALL, CMPLT_WH_SPTK, CMPLT_PH_MANY, pred, convOpnd, b0, callTgt); |
| |
| opndManager->setContainCall(true); // set flag OpndManager::containCall (method contains call) |
| makeCallArgs(numArgs, args, callInst, pred); // add instructions moving args in appropriate locations |
| |
| addInst(ldAddress); // add inst loading method address |
| addInst(callInst); // add "call" inst |
| makeRetVal(retOpnd, convOpnd, pred); // add instruction moving ret value from r8/f8 |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Move out args in regs and stack positions according with IPF software convention |
| |
| void IpfInstCodeSelector::makeCallArgs(U_32 numArgs, Opnd **args, Inst *callInst, RegOpnd *pred) { |
| |
| int16 numFpOutArgs = 0; |
| for(U_32 argPosition=0; argPosition<numArgs; argPosition++) { |
| |
| Opnd *opnd = args[argPosition]; |
| OpndKind opndKind = OPND_INVALID; |
| DataKind dataKind = DATA_INVALID; |
| InstCode instCode = INST_INVALID; |
| I_32 location = LOCATION_INVALID; |
| bool isFp = opnd->isFloating(); |
| |
| if (opnd->isReg() == true) { // opnd is register |
| opndKind = opnd->getOpndKind(); // outArg has the same opndKind |
| dataKind = opnd->getDataKind(); // outArg has the same dataKind |
| instCode = INST_MOV; |
| } else { // opnd is imm |
| opndKind = OPND_G_REG; |
| dataKind = DATA_U64; |
| instCode = opnd->isFoldableImm(22) ? INST_MOV : INST_MOVL; |
| } |
| |
| if (argPosition < MAX_REG_ARG) { // arg is going on register |
| if (isFp) location = F_OUTARG_BASE + numFpOutArgs++; // real location |
| else location = opndManager->newOutReg(argPosition); // temporary location |
| } else { // arg is going on stack |
| location = opndManager->newOutSlot(argPosition); // location is area local offset |
| } |
| |
| Opnd *outArg = opndManager->newRegOpnd(opndKind, dataKind, location); |
| |
| addNewInst(instCode, pred, outArg, opnd); |
| callInst->addOpnd(outArg); // add the opnd in call opnds list (for data flow analysis) |
| } |
| } |
| |
| //----------------------------------------------------------------------------// |
| // make opnd representing return value of method (r8/f8) |
| |
| RegOpnd *IpfInstCodeSelector::makeConvOpnd(RegOpnd *retOpnd) { |
| |
| if(retOpnd == NULL) return opndManager->getR0(); // method has return type "void" |
| |
| if (retOpnd->isFloating()) return opndManager->getF8(); |
| else return opndManager->getR8(); |
| } |
| |
| //----------------------------------------------------------------------------// |
| // create mov to free r8/f8 |
| |
| void IpfInstCodeSelector::makeRetVal(RegOpnd *retOpnd, RegOpnd *convOpnd, RegOpnd *pred) { |
| |
| if(retOpnd == NULL) return; // method has return type "void" |
| |
| addNewInst(INST_MOV, pred, retOpnd, convOpnd); |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Generate "cmp" instruction for two opnds (int, float or imm). |
| |
| void IpfInstCodeSelector::cmp(InstCode instCode, |
| Completer cmpRelation, |
| RegOpnd *truePred, |
| RegOpnd *falsePred, |
| CG_OpndHandle *src1_, |
| CG_OpndHandle *src2_) { |
| |
| RegOpnd *src1 = toRegOpnd(src1_); |
| RegOpnd *src2 = toRegOpnd(src2_); |
| |
| if (instCode == INST_CMP) { sxt(src1, 8); sxt(src2, 8); } |
| if (instCode == INST_CMP4) { sxt(src1, 4); sxt(src2, 4); } |
| |
| addNewInst(instCode, cmpRelation, p0, truePred, falsePred, src1, src2); |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Choose and generate appropriate "cmp" instruction for two opnds (int, float or imm). |
| |
| void IpfInstCodeSelector::cmp(Completer cmpRelation, |
| RegOpnd *truePred, |
| RegOpnd *falsePred, |
| CG_OpndHandle *src1_, |
| CG_OpndHandle *src2_) { |
| |
| Opnd *src1 = (Opnd *)src1_; |
| Opnd *src2 = (Opnd *)src2_; |
| |
| // fcmp |
| if (src1->isFloating() || src2->isFloating()) { |
| cmp(INST_FCMP, cmpRelation, truePred, falsePred, src1, src2); |
| return; |
| } |
| |
| // cmp |
| if (src1->getSize()>4 || src1->getSize()>4) { |
| cmp(INST_CMP, cmpRelation, truePred, falsePred, src1, src2); |
| return; |
| } |
| |
| // cmp4 |
| cmp(INST_CMP4, cmpRelation, truePred, falsePred, src1, src2); |
| } |
| |
| //----------------------------------------------------------------------------// |
| |
| void IpfInstCodeSelector::sxt(CG_OpndHandle *src_, int16 refSize, Completer srcSize) { |
| |
| Opnd *src = (Opnd *)src_; |
| |
| if (src->isReg() == false) return; // ignore non reg opnd (imm) |
| if (src->isFloating() == true) return; // ignore fp opnd |
| if (src->isSigned() == false) return; // ignore unsigned opnd |
| |
| Completer cmplt = (srcSize==CMPLT_INVALID ? toCmpltSz(src->getDataKind()) : srcSize); |
| int16 srcbytes = (cmplt==CMPLT_SZ_1 ? 1 : (cmplt==CMPLT_SZ_2 ? 2 : (cmplt==CMPLT_SZ_4?4:8))); |
| if (srcbytes >= refSize) return; // nothing to do |
| |
| addNewInst(INST_SXT, cmplt, p0, src, src); |
| } |
| |
| //----------------------------------------------------------------------------// |
| |
| void IpfInstCodeSelector::zxt(CG_OpndHandle *src_, int16 refSize, Completer srcSize) { |
| |
| Opnd *src = (Opnd *)src_; |
| |
| if (src->isReg() == false) return; // ignore non reg opnd (imm) |
| if (src->isFloating() == true) return; // ignore fp opnd |
| |
| Completer cmplt = (srcSize==CMPLT_INVALID?toCmpltSz(src->getDataKind()):srcSize); |
| int16 srcbytes = (cmplt==CMPLT_SZ_1?1:(cmplt==CMPLT_SZ_2?2:(cmplt==CMPLT_SZ_4?4:8))); |
| if (srcbytes >= refSize) return; // nothing to do |
| |
| addNewInst(INST_ZXT, cmplt, p0, src, src); |
| } |
| |
| //----------------------------------------------------------------------------// |
| // If opnd is imm this method generates "mov" from imm to gr |
| // if imm==0 then return r0 |
| // |
| RegOpnd *IpfInstCodeSelector::toRegOpnd(CG_OpndHandle *opnd_) { |
| |
| if(((Opnd *)opnd_)->isReg()) return (RegOpnd *)opnd_; |
| IPF_ASSERT(((Opnd *)opnd_)->isImm()); |
| |
| Opnd *opnd = (Opnd *)opnd_; |
| if (opnd->getValue()==0) { |
| return opndManager->getR0(); |
| } else { |
| RegOpnd *dst = opndManager->newRegOpnd(OPND_G_REG, DATA_I64); |
| InstCode instCode = opnd->isFoldableImm(22) ? INST_MOV : INST_MOVL; |
| |
| addNewInst(instCode, p0, dst, opnd); |
| return dst; |
| } |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Add int or fp values |
| |
| void IpfInstCodeSelector::add(RegOpnd *dst, CG_OpndHandle *src1_, CG_OpndHandle *src2_) { |
| |
| Opnd *src1 = (Opnd *)src1_; |
| Opnd *src2 = (Opnd *)src2_; |
| |
| // fadd fr, fr |
| if(dst->isFloating()) { |
| Completer cmplt = CMPLT_PC_DYNAMIC; |
| |
| switch (dst->getDataKind()) { |
| case DATA_D: cmplt = CMPLT_PC_DOUBLE; break; |
| case DATA_S: cmplt = CMPLT_PC_SINGLE; break; |
| default: IPF_ERR << "bad data kind for float add\n"; break; |
| } |
| addNewInst(INST_FADD, cmplt, p0, dst, src1, src2); |
| return; |
| } |
| |
| sxt(src1, dst->getSize()); // sxt src1 if appropriate |
| sxt(src2, dst->getSize()); // sxt src2 if appropriate |
| |
| // imm opnd must be on first position |
| if(src2->isImm()) { |
| Opnd *buf = src1; |
| src1 = src2; |
| src2 = toRegOpnd(buf); |
| } |
| |
| // add imm, gr |
| if (src1->isImm()) { |
| // imm14 |
| if(src1->isFoldableImm(14)) { |
| addNewInst(INST_ADDS, p0, dst, src1, src2); |
| return; |
| } |
| // imm |
| RegOpnd *buf = toRegOpnd(src1); |
| addNewInst(INST_ADD, p0, dst, buf, src2); |
| return; |
| } |
| |
| // add gr, gr |
| addNewInst(INST_ADD, p0, dst, src1, src2); |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Sub int or fp values |
| |
| void IpfInstCodeSelector::sub(RegOpnd *dst, CG_OpndHandle *src1_, CG_OpndHandle *src2_) { |
| |
| Opnd *src1 = (Opnd *)src1_; |
| Opnd *src2 = (Opnd *)src2_; |
| |
| // sub fr, fr |
| if(dst->isFloating()) { |
| Completer cmplt = CMPLT_PC_DYNAMIC; |
| |
| switch (dst->getDataKind()) { |
| case DATA_D: cmplt = CMPLT_PC_DOUBLE; break; |
| case DATA_S: cmplt = CMPLT_PC_SINGLE; break; |
| default: IPF_ERR << "bad data kind for float sub\n"; break; |
| } |
| addNewInst(INST_FSUB, cmplt, p0, dst, src1, src2); |
| return; |
| } |
| |
| sxt(src1, dst->getSize()); // sxt src1 if appropriate |
| sxt(src2, dst->getSize()); // sxt src2 if appropriate |
| |
| // imm opnd must be on first position |
| if(src2->isImm()) { |
| Opnd *buf = src2; |
| src2 = toRegOpnd(buf); |
| } |
| |
| // sub imm, gr |
| if (src1->isImm()) { |
| |
| // imm8 |
| if(src1->isFoldableImm(8)) { |
| addNewInst(INST_SUB, p0, dst, src1, src2); |
| return; |
| } |
| |
| // imm |
| RegOpnd *buf = toRegOpnd(src1); |
| addNewInst(INST_SUB, p0, dst, buf, src2); |
| return; |
| } |
| |
| // sub gr, gr |
| addNewInst(INST_SUB, p0, dst, src1, src2); |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Only INST_AND, INST_OR, INST_XOR |
| |
| void IpfInstCodeSelector::binOp(InstCode instCode, |
| RegOpnd *dst, |
| CG_OpndHandle *src1_, |
| CG_OpndHandle *src2_) { |
| |
| IPF_ASSERT(instCode==INST_AND || instCode==INST_OR || instCode==INST_XOR); |
| |
| Opnd *src1 = (Opnd *)src1_; |
| Opnd *src2 = (Opnd *)src2_; |
| |
| IPF_ASSERT(src1->isReg() || src2->isReg()); |
| |
| // imm opnd must be on first position |
| if(src2->isImm()) { |
| Opnd *buf = src1; |
| src1 = src2; |
| src2 = toRegOpnd(buf); |
| } |
| |
| sxt(src1, dst->getSize()); // sxt src1 if appropriate |
| sxt(src2, dst->getSize()); // sxt src2 if appropriate |
| |
| // sub imm, gr |
| if (src1->isImm()) { |
| |
| // imm8 |
| if(src1->isFoldableImm(8)) { |
| addNewInst(instCode, p0, dst, src1, src2); |
| return; |
| } |
| |
| // imm |
| RegOpnd *buf = toRegOpnd(src1); |
| addNewInst(instCode, p0, dst, buf, src2); |
| return; |
| } |
| |
| // sub gr, gr |
| addNewInst(instCode, p0, dst, src1, src2); |
| } |
| |
| //----------------------------------------------------------------------------// |
| |
| void IpfInstCodeSelector::shift(InstCode instCode, |
| RegOpnd *dst, |
| CG_OpndHandle *value_, |
| CG_OpndHandle *count_, |
| int bits) { |
| |
| RegOpnd *value = toRegOpnd(value_); |
| Opnd *count = (Opnd *)count_; |
| |
| sxt(value, dst->getSize()); |
| |
| if (count->isImm()) { |
| if (!count->isFoldableImm(bits)) { |
| // RegOpnd *tmp = toRegOpnd(count); |
| // |
| // addNewInst(INST_AND, p0, tmp, opndManager->newImm(bits==5?0x1F:0x2F), tmp); |
| count = opndManager->newImm(count->getValue() & (bits==5?0x1F:0x3F)); |
| } |
| } else { |
| RegOpnd *tmp = (RegOpnd *)count; |
| |
| if (value_==count_) { |
| tmp = opndManager->newRegOpnd(OPND_G_REG, count->getDataKind()); |
| addNewInst(INST_MOV, p0, tmp, count); |
| } |
| |
| addNewInst(INST_AND, p0, tmp, opndManager->newImm(bits==5?0x1F:0x3F), tmp); |
| count = tmp; |
| } |
| |
| // shx gr = gr, imm |
| if (count->isImm()) { |
| |
| // imm6 |
| if(count->isFoldableImm(6)) { |
| addNewInst(instCode, p0, dst, value, count); |
| return; |
| } |
| |
| // imm |
| RegOpnd *buf = toRegOpnd(count); |
| addNewInst(instCode, p0, dst, value, buf); |
| return; |
| } |
| |
| // shx gr = gr, gr |
| addNewInst(instCode, p0, dst, value, count); |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Load N-bit integer constant |
| |
| void IpfInstCodeSelector::ldc(RegOpnd *dst, int64 val) { |
| |
| // if (val == 0) { |
| // IPF_LOG << " opnd \"r0\"" << endl; |
| // return dst->setLocation(0); |
| // } |
| |
| Opnd *immOpnd = opndManager->newImm(val); |
| InstCode instCode = immOpnd->isFoldableImm(22) ? INST_MOV : INST_MOVL; |
| |
| addNewInst(instCode, p0, dst, immOpnd); |
| } |
| |
| //----------------------------------------------------------------------------// |
| |
| void IpfInstCodeSelector::minMax(RegOpnd *dst, |
| CG_OpndHandle *src1_, |
| CG_OpndHandle *src2_, |
| bool max) { |
| |
| Opnd *src1 = (Opnd *)src1_; |
| Opnd *src2 = (Opnd *)src2_; |
| |
| if (dst->isFloating()) { |
| // TODO: check all the peculiarities of Math.min/max |
| InstCode instCode = max ? INST_FMAX : INST_FMIN; |
| addNewInst(instCode, p0, dst, src1, src2); |
| } else { |
| Completer crel = max ? CMPLT_CMP_CREL_LT : CMPLT_CMP_CREL_GT; |
| RegOpnd *truePred = opndManager->newRegOpnd(OPND_P_REG, DATA_P); |
| RegOpnd *falsePred = opndManager->newRegOpnd(OPND_P_REG, DATA_P); |
| |
| cmp(crel, truePred, falsePred, src1, src2); |
| addNewInst(INST_MOV, truePred, dst, src1); |
| addNewInst(INST_MOV, falsePred, dst, src2); |
| } |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Generate instruction sequence for integer multiplication |
| |
| void IpfInstCodeSelector::xma(InstCode instCode, |
| RegOpnd *dst, |
| CG_OpndHandle *src1, |
| CG_OpndHandle *src2) { |
| |
| IPF_ASSERT(((Opnd *)src1)->isReg()); |
| IPF_ASSERT(((Opnd *)src2)->isReg()); |
| |
| RegOpnd *f0 = opndManager->getF0(); |
| RegOpnd *buf1 = opndManager->newRegOpnd(OPND_F_REG, DATA_D); |
| RegOpnd *buf2 = opndManager->newRegOpnd(OPND_F_REG, DATA_D); |
| RegOpnd *dstF = opndManager->newRegOpnd(OPND_F_REG, DATA_D); |
| |
| sxt(src1, 8); // sxt src1 if appropriate |
| sxt(src2, 8); // sxt src2 if appropriate |
| |
| addNewInst(INST_SETF_SIG, p0, buf1, src1); |
| addNewInst(INST_SETF_SIG, p0, buf2, src2); |
| addNewInst(instCode, p0, dstF, buf1, buf2, f0); |
| addNewInst(INST_GETF_SIG, p0, dst, dstF); |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Convert floating-point to 64-bit integer with saturation |
| // |
| // ldfd tf1 = ALMOST_MAXINT8 (see below for details) |
| // mov t1 = -1 |
| // fcvt.fx tf2 = src |
| // fcmp.gt p1 = src, tf1 |
| // fcmp.unord p2 = src, src |
| // getf.sig dst = tf2 |
| // (p1) shr.u dst = t1, 1 |
| // (p2) mov dst = 0 |
| // |
| |
| void IpfInstCodeSelector::saturatingConv8(RegOpnd *dst, CG_OpndHandle *src_) { |
| |
| IPF_LOG << " saturatingConv8" << endl; |
| |
| IPF_ASSERT(((Opnd *)src_)->isFloating()); |
| |
| RegOpnd *src = (RegOpnd *)src_; |
| RegOpnd *tf1 = NULL; |
| RegOpnd *tf2 = opndManager->newRegOpnd(OPND_F_REG, src->getDataKind()); |
| RegOpnd *p1 = opndManager->newRegOpnd(OPND_P_REG, DATA_P); |
| RegOpnd *p2 = opndManager->newRegOpnd(OPND_P_REG, DATA_P); |
| RegOpnd *t1 = opndManager->newRegOpnd(OPND_G_REG, dst->getDataKind()); |
| |
| if (src->getDataKind() == DATA_S) { |
| // maximal int64 that is exactly representable in single FP format |
| tf1 = (RegOpnd *)ldc_s((float)__INT64_C(0x7fffff0000000000)); |
| } else { |
| // maximal int64 that is exactly representable in double FP format |
| int64 max_int64 = __INT64_C(0x7ffffffffffff800); |
| tf1 = (RegOpnd *)ldc_d((double)max_int64); |
| } |
| |
| sxt(src, 8); // sxt src if appropriate |
| addNewInst(INST_MOV, p0, t1, opndManager->newImm(-1)); |
| addNewInst(INST_FCVT_FX_TRUNC, p0, tf2, src); |
| addNewInst(INST_FCMP, CMPLT_CMP_CREL_GT, CMPLT_FCMP_FCTYPE_NONE, p0, p1, p0, src, tf1); |
| addNewInst(INST_FCMP, CMPLT_FCMP_FREL_UNORD, CMPLT_FCMP_FCTYPE_NONE, p0, p2, p0, src, src); |
| addNewInst(INST_GETF_SIG, p0, dst, tf2); |
| addNewInst(INST_SHR_U, p1, dst, t1, opndManager->newImm(1)); |
| addNewInst(INST_MOV, p2, dst, opndManager->newImm(0)); |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Convert floating-point to 32-bit integer with saturation. Then sign/zero |
| // extend based on dstType. |
| // |
| // ldfd tf1 = MAXINT4 |
| // ldfd tf2 = MININT4 |
| // mov t1 = -1 |
| // fcvt.fx tf3 = src |
| // fcmp.gt p1 = src, tf1 |
| // fcmp.lt p2 = src, tf2 |
| // getf.sig t2 = tf3 |
| // sxt4 dst = t2 |
| // (p1) shr.u dst = t1, 33 |
| // (p2) shl dst = t1, 31 |
| // |
| // New code |
| // ldfd tf = MAXINT4 |
| // fcmp.lt p11,p10 = src, tf |
| // (p10) movl dst = 0x7fffffff |
| // (p10) cmp.ne p10 = r0,r0 |
| // |
| // (p11) ldfd tf = MININT4 |
| // (p11) fcmp.gt p11,p10 = src, tf |
| // (p10) movl dst = 0x80000000 |
| // |
| // (p11) fcvt.fx tf = src |
| // (p11) getf.sig dst = tf |
| |
| void IpfInstCodeSelector::saturatingConv4(RegOpnd *dst, CG_OpndHandle *src_) { |
| |
| IPF_LOG << " saturatingConv4" << endl; |
| |
| IPF_ASSERT(((Opnd *)src_)->isFloating()); |
| |
| union { |
| float fr; |
| U_32 gr; |
| } fval; |
| union { |
| double fr; |
| uint64 gr; |
| } dval; |
| |
| RegOpnd *r0 = opndManager->getR0(); |
| RegOpnd *src = (RegOpnd *)src_; |
| RegOpnd *p11 = opndManager->newRegOpnd(OPND_P_REG, DATA_P); |
| RegOpnd *p10 = opndManager->newRegOpnd(OPND_P_REG, DATA_P); |
| RegOpnd *tf = NULL; |
| RegOpnd *tr = opndManager->newRegOpnd(OPND_G_REG, DATA_I64); |
| |
| if (src->getDataKind() == DATA_S) { |
| tf = opndManager->newRegOpnd(OPND_F_REG, DATA_S); |
| fval.fr = (float)0x7fffffff; |
| addNewInst(INST_MOVL, p0, tr, opndManager->newImm(fval.gr)); |
| addNewInst(INST_SETF_S, p0, tf, tr); |
| } else { |
| tf = opndManager->newRegOpnd(OPND_F_REG, DATA_D); |
| dval.fr = (double)0x7fffffff; |
| addNewInst(INST_MOVL, p0, tr, opndManager->newImm(dval.gr)); |
| addNewInst(INST_SETF_D, p0, tf, tr); |
| } |
| addNewInst(INST_FCMP, CMPLT_CMP_CREL_LT, p0, p11, p10, src, tf); |
| addNewInst(INST_MOVL, p10, dst, opndManager->newImm(0x7fffffff)); |
| addNewInst(INST_CMP, CMPLT_CMP_CREL_NE, p10, p10, p0, r0, r0); |
| |
| if (src->getDataKind() == DATA_S) { |
| fval.fr = (float)((int)0x80000000); |
| addNewInst(INST_MOVL, p11, tr, opndManager->newImm(fval.gr)); |
| addNewInst(INST_SETF_S, p11, tf, tr); |
| } else { |
| tf = opndManager->newRegOpnd(OPND_F_REG, DATA_D); |
| dval.fr = (double)((int) 0x80000000); |
| addNewInst(INST_MOVL, p11, tr, opndManager->newImm(dval.gr)); |
| addNewInst(INST_SETF_D, p11, tf, tr); |
| } |
| addNewInst(INST_FCMP, CMPLT_CMP_CREL_GT, p11, p11, p10, src, tf); |
| addNewInst(INST_MOVL, p10, dst, opndManager->newImm(0x80000000)); |
| |
| addNewInst(INST_FCVT_FX_TRUNC, p11, tf, src); |
| addNewInst(INST_GETF_SIG, p11, dst, tf); |
| |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Divide two integer values. |
| |
| void IpfInstCodeSelector::divInt(RegOpnd *dst, CG_OpndHandle *src1, CG_OpndHandle *src2, bool rem) { |
| |
| IPF_ASSERT(((Opnd *)src1)->isReg()); |
| IPF_ASSERT(((Opnd *)src2)->isReg()); |
| |
| RegOpnd *f0 = opndManager->getF0(); |
| RegOpnd *f1 = opndManager->getF1(); |
| RegOpnd *p6 = opndManager->newRegOpnd(OPND_P_REG, DATA_P); |
| RegOpnd *f6 = opndManager->newRegOpnd(OPND_F_REG, DATA_D); |
| RegOpnd *f7 = opndManager->newRegOpnd(OPND_F_REG, DATA_D); |
| RegOpnd *f8 = opndManager->newRegOpnd(OPND_F_REG, DATA_D); |
| RegOpnd *f9 = opndManager->newRegOpnd(OPND_F_REG, DATA_D); |
| RegOpnd *f10 = opndManager->newRegOpnd(OPND_F_REG, DATA_D); |
| |
| sxt(src1, 8); |
| sxt(src2, 8); |
| |
| addNewInst(INST_DEF, p0,f6 ); |
| addNewInst(INST_DEF, p0,f7 ); |
| addNewInst(INST_DEF, p0,f8 ); |
| addNewInst(INST_DEF, p0,f9 ); |
| addNewInst(INST_DEF, p0,f10); |
| |
| addNewInst(INST_SETF_SIG, p0, f10, src1); |
| addNewInst(INST_SETF_SIG, p0, f9, src2); |
| addNewInst(INST_FCVT_XF, p0, f6, f10); |
| addNewInst(INST_FCVT_XF, p0, f7, f9); |
| addNewInst(INST_MOV, p0, dst, opndManager->newImm(0x0ffdd)); |
| addNewInst(INST_SETF_EXP, p0, f9, dst); |
| |
| addNewInst(INST_FRCPA, p0, f8, p6, f6, f7); |
| addNewInst(INST_FMA, p6, f6, f6, f8, f0); |
| addNewInst(INST_FNMA, p6, f7, f7, f8, f1); |
| addNewInst(INST_FMA, p6, f6, f7, f6, f6); |
| addNewInst(INST_FMA, p6, f7, f7, f7, f9); |
| addNewInst(INST_FMA, p6, f8, f7, f6, f6); |
| addNewInst(INST_FCVT_FX_TRUNC, p0, f8, f8); |
| |
| if (rem) { |
| RegOpnd *msrc2 = opndManager->newRegOpnd(OPND_G_REG, DATA_I64); |
| addNewInst(INST_SUB, p0, msrc2, opndManager->getR0(), src2); |
| addNewInst(INST_SETF_SIG, p0, f9, msrc2); |
| addNewInst(INST_XMA_L, p0, f8, f9, f8, f10); |
| } |
| |
| // result is in the least significant 32 bits of r8 (if b != 0) |
| addNewInst(INST_GETF_SIG, p0, dst, f8); |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Divide two long values. |
| |
| void IpfInstCodeSelector::divLong(RegOpnd *dst, CG_OpndHandle *src1, CG_OpndHandle *src2, bool rem) { |
| |
| IPF_ASSERT(((Opnd *)src1)->isReg()); |
| IPF_ASSERT(((Opnd *)src2)->isReg()); |
| |
| RegOpnd *f0 = opndManager->getF0(); |
| RegOpnd *f1 = opndManager->getF1(); |
| RegOpnd *p6 = opndManager->newRegOpnd(OPND_P_REG, DATA_P); |
| RegOpnd *f6 = opndManager->newRegOpnd(OPND_F_REG, DATA_D); |
| RegOpnd *f7 = opndManager->newRegOpnd(OPND_F_REG, DATA_D); |
| RegOpnd *f8 = opndManager->newRegOpnd(OPND_F_REG, DATA_D); |
| RegOpnd *f9 = opndManager->newRegOpnd(OPND_F_REG, DATA_D); |
| RegOpnd *f10 = opndManager->newRegOpnd(OPND_F_REG, DATA_D); |
| |
| sxt(src1, 8); |
| sxt(src2, 8); |
| |
| addNewInst(INST_DEF, p0,f6 ); |
| addNewInst(INST_DEF, p0,f7 ); |
| addNewInst(INST_DEF, p0,f8 ); |
| addNewInst(INST_DEF, p0,f9 ); |
| addNewInst(INST_DEF, p0,f10); |
| |
| addNewInst(INST_SETF_SIG, p0, f10, src1); |
| addNewInst(INST_SETF_SIG, p0, f9, src2); |
| |
| addNewInst(INST_FCVT_XF, p0, f6, f10); |
| addNewInst(INST_FCVT_XF, p0, f7, f9); |
| |
| addNewInst(INST_FRCPA, p0, f8, p6, f6, f7); |
| addNewInst(INST_FNMA, p6, f9, f7, f8, f1); |
| addNewInst(INST_FMA, p6, f8, f9, f8, f8); |
| addNewInst(INST_FMA, p6, f9, f9, f9, f0); |
| addNewInst(INST_FMA, p6, f8, f9, f8, f8); |
| addNewInst(INST_FMA, p6, f9, f8, f6, f0); |
| addNewInst(INST_FNMA, p6, f7, f7, f9, f6); |
| addNewInst(INST_FMA, p6, f8, f7, f8, f9); |
| addNewInst(INST_FCVT_FX_TRUNC, p0, f8, f8); |
| |
| if (rem) { |
| RegOpnd *msrc2 = opndManager->newRegOpnd(OPND_G_REG, DATA_I64); |
| addNewInst(INST_SUB, p0, msrc2, opndManager->getR0(), src2); |
| addNewInst(INST_SETF_SIG, p0, f9, msrc2); |
| addNewInst(INST_XMA_L, p0, f8, f9, f8, f10); |
| } |
| |
| addNewInst(INST_GETF_SIG, p0, dst, f8); |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Divide two double values. |
| |
| void IpfInstCodeSelector::divDouble(RegOpnd *dst, CG_OpndHandle *src1, CG_OpndHandle *src2, bool rem) { |
| |
| IPF_ASSERT(((Opnd *)src1)->isReg()); |
| IPF_ASSERT(((Opnd *)src2)->isReg()); |
| |
| if (!rem) { |
| RegOpnd *f0 = opndManager->getF0(); |
| RegOpnd *f1 = opndManager->getF1(); |
| |
| RegOpnd *fRes = dst, *fA = (RegOpnd *)src1, *fB = (RegOpnd *)src2; |
| RegOpnd *pX = opndManager->newRegOpnd(OPND_P_REG, DATA_P); |
| RegOpnd *fe = opndManager->newRegOpnd(OPND_F_REG, DATA_F); |
| RegOpnd *fq0 = opndManager->newRegOpnd(OPND_F_REG, DATA_F); |
| RegOpnd *fq1 = opndManager->newRegOpnd(OPND_F_REG, DATA_F); |
| RegOpnd *fe2 = opndManager->newRegOpnd(OPND_F_REG, DATA_F); |
| RegOpnd *fy1 = opndManager->newRegOpnd(OPND_F_REG, DATA_F); |
| RegOpnd *fe4 = opndManager->newRegOpnd(OPND_F_REG, DATA_F); |
| RegOpnd *fq2 = opndManager->newRegOpnd(OPND_F_REG, DATA_F); |
| RegOpnd *fy2 = opndManager->newRegOpnd(OPND_F_REG, DATA_F); |
| RegOpnd *fq3 = opndManager->newRegOpnd(OPND_F_REG, DATA_F); |
| RegOpnd *fy3 = opndManager->newRegOpnd(OPND_F_REG, DATA_F); |
| RegOpnd *fr = opndManager->newRegOpnd(OPND_F_REG, DATA_F); |
| |
| // |
| // Group 0 |
| // frcpa.s0 fRes,pX = fA,fB |
| // Group 1 |
| // (pX) fnma.s1 fe = fRes,fB,f1 |
| // (pX) fmpy.s1 fq0 = fA,fRes |
| // Group 2 |
| // (pX) fmpy.s1 fe2 = fe,fe |
| // (pX) fma.s1 fq1 = fq0,fe,fq0 |
| // (pX) fma.s1 fy1 = fRes,fe,fRes |
| // Group 3 |
| // (pX) fmpy.s1 fe4 = fe2,fe2 |
| // (pX) fma.s1 fq2 = fq1,fe2,fq1 |
| // (pX) fma.s1 fy2 = fy1,fe2,fy1 |
| // Group 4 |
| // (pX) fma.d.s1 fq3 = fq2,fe4,fq2 |
| // (pX) fma.s1 fy3 = fy2,fe4,fy2 |
| // Group 5 |
| // (pX) fnma.s1 fr = fB,fq3,fA |
| // Group 6 |
| // (pX) fma.d.s0 fRes = fr,fy3,fq3 |
| // |
| addNewInst(INST_DEF, p0, fe ); |
| addNewInst(INST_DEF, p0, fq0); |
| addNewInst(INST_DEF, p0, fq1); |
| addNewInst(INST_DEF, p0, fe2); |
| addNewInst(INST_DEF, p0, fy1); |
| addNewInst(INST_DEF, p0, fe4); |
| addNewInst(INST_DEF, p0, fq2); |
| addNewInst(INST_DEF, p0, fy2); |
| addNewInst(INST_DEF, p0, fq3); |
| addNewInst(INST_DEF, p0, fy3); |
| addNewInst(INST_DEF, p0, fr ); |
| |
| addNewInst(INST_FRCPA, CMPLT_SF0, p0, fRes, pX, fA, fB); |
| |
| addNewInst(INST_FNMA, CMPLT_SF1, pX, fe, fRes, fB, f1); |
| addNewInst(INST_FMA, CMPLT_SF1, pX, fq0, fA, fRes, f0); |
| |
| addNewInst(INST_FMA, CMPLT_SF1, pX, fe2, fe, fe, f0); |
| addNewInst(INST_FMA, CMPLT_SF1, pX, fq1, fq0, fe, fq0); |
| addNewInst(INST_FMA, CMPLT_SF1, pX, fy1, fRes, fe, fRes); |
| |
| addNewInst(INST_FMA, CMPLT_SF1, pX, fe4, fe2, fe2, f0); |
| addNewInst(INST_FMA, CMPLT_SF1, pX, fq2, fq1, fe2, fq1); |
| addNewInst(INST_FMA, CMPLT_SF1, pX, fy2, fy1, fe2, fy1); |
| |
| addNewInst(INST_FMA, CMPLT_PC_DOUBLE, CMPLT_SF1, pX, fq3, fq2, fe4, fq2); |
| addNewInst(INST_FMA, CMPLT_SF1, pX, fy3, fy2, fe4, fy2); |
| |
| addNewInst(INST_FNMA, CMPLT_SF1, pX, fr, fB, fq3, fA); |
| |
| addNewInst(INST_FMA, CMPLT_PC_DOUBLE, CMPLT_SF0, pX, fRes, fr, fy3, fq3); |
| } else { |
| // Call internal helper to do FP remainder. We only inline the integer |
| // remainder sequence |
| // |
| Opnd *helperArgs[] = { (Opnd *)src1, (Opnd *)src2 }; |
| |
| uint64 address = (uint64) remF8; |
| Opnd *helperAddress = opndManager->newImm(address); |
| |
| directCall(2, helperArgs, dst, helperAddress, p0); |
| } |
| } |
| |
| //----------------------------------------------------------------------------// |
| |
| CG_OpndHandle *IpfInstCodeSelector::ldRef(Type *dstType, |
| MethodDesc* enclosingMethod, |
| U_32 refToken, |
| bool uncompress) |
| { |
| assert(dstType->isSystemString() || dstType->isSystemClass()); |
| |
| RegOpnd *retOpnd = opndManager->newRegOpnd(OPND_G_REG, toDataKind(dstType->tag)); |
| Opnd *helperArgs[] = { |
| opndManager->newImm(refToken), |
| opndManager->newImm((int64) enclosingMethod->getParentType()->getRuntimeIdentifier()) |
| }; |
| VM_RT_SUPPORT hId = VM_RT_LDC_STRING; |
| uint64 address = (uint64) compilationInterface.getRuntimeHelperAddress(hId); |
| Opnd *helperAddress = opndManager->newImm(address); |
| |
| directCall(2, helperArgs, retOpnd, helperAddress, p0); |
| |
| return retOpnd; |
| } |
| |
| //----------------------------------------------------------------------------// |
| |
| void IpfInstCodeSelector::methodEntry(MethodDesc *meth) { |
| |
| if (compilationInterface.getCompilationParams().exe_notify_method_entry) { |
| NOT_IMPLEMENTED_V("methodEntry"); |
| } |
| |
| } |
| |
| void IpfInstCodeSelector::methodEnd(MethodDesc *meth, CG_OpndHandle *retopnd) { |
| |
| if (compilationInterface.getCompilationParams().exe_notify_method_exit) { |
| NOT_IMPLEMENTED_V("methodEnd"); |
| } |
| |
| } |
| |
| //----------------------------------------------------------------------------// |
| // Divide two float values. |
| |
| void IpfInstCodeSelector::divFloat(RegOpnd *dst, CG_OpndHandle *src1, CG_OpndHandle *src2, bool rem) { |
| |
| IPF_ASSERT(((Opnd *)src1)->isReg()); |
| IPF_ASSERT(((Opnd *)src2)->isReg()); |
| |
| if (!rem) { |
| RegOpnd *f0 = opndManager->getF0(); |
| RegOpnd *f1 = opndManager->getF1(); |
| |
| RegOpnd *fRes = dst, *fA = (RegOpnd *)src1, *fB = (RegOpnd *)src2; |
| RegOpnd *pX = opndManager->newRegOpnd(OPND_P_REG, DATA_P); |
| RegOpnd *fe = opndManager->newRegOpnd(OPND_F_REG, DATA_F); |
| RegOpnd *fq0 = opndManager->newRegOpnd(OPND_F_REG, DATA_F); |
| RegOpnd *fq1 = opndManager->newRegOpnd(OPND_F_REG, DATA_F); |
| RegOpnd *fe2 = opndManager->newRegOpnd(OPND_F_REG, DATA_F); |
| RegOpnd *fe4 = opndManager->newRegOpnd(OPND_F_REG, DATA_F); |
| RegOpnd *fq2 = opndManager->newRegOpnd(OPND_F_REG, DATA_F); |
| RegOpnd *fq3 = opndManager->newRegOpnd(OPND_F_REG, DATA_F); |
| |
| // |
| // Group 0 |
| // frcpa.s0 fRes,pX = fA,fB |
| // Group 1 |
| // (pX) fnma.s1 fe = fRes,fB,f1 |
| // (pX) fmpy.s1 fq0 = fA,fRes |
| // Group 2 |
| // (pX) fmpy.s1 fe2 = fe,fe |
| // (pX) fma.s1 fq1 = fq0,fe,fq0 |
| // Group 3 |
| // (pX) fmpy.s1 fe4 = fe2,fe2 |
| // (pX) fma.s1 fq2 = fq1,fe2,fq1 |
| // Group 4 |
| // (pX) fma.d.s1 fq3 = fq2,fe4,fq2 |
| // (pX) fnorm.s.s0 fRes = fq3 |
| // |
| |
| addNewInst(INST_DEF, p0, fe ); |
| addNewInst(INST_DEF, p0, fq0); |
| addNewInst(INST_DEF, p0, fq1); |
| addNewInst(INST_DEF, p0, fe2); |
| addNewInst(INST_DEF, p0, fe4); |
| addNewInst(INST_DEF, p0, fq2); |
| addNewInst(INST_DEF, p0, fq3); |
| |
| addNewInst(INST_FRCPA, CMPLT_SF0, p0, fRes, pX, fA, fB); |
| |
| addNewInst(INST_FNMA, CMPLT_SF1, pX, fe, fRes, fB, f1); |
| addNewInst(INST_FMA, CMPLT_SF1, pX, fq0, fA, fRes, f0); |
| |
| addNewInst(INST_FMA, CMPLT_SF1, pX, fe2, fe, fe, f0); |
| addNewInst(INST_FMA, CMPLT_SF1, pX, fq1, fq0, fe, fq0); |
| |
| addNewInst(INST_FMA, CMPLT_SF1, pX, fe4, fe2, fe2, f0); |
| addNewInst(INST_FMA, CMPLT_SF1, pX, fq2, fq1, fe2, fq1); |
| |
| addNewInst(INST_FMA, CMPLT_PC_DOUBLE, CMPLT_SF1, pX, fq3, fq2, fe4, fq2); |
| addNewInst(INST_FNORM, CMPLT_PC_SINGLE, CMPLT_SF0, pX, fRes, fq3); |
| } else { |
| // Call internal helper to do FP remainder. We only inline the integer |
| // remainder sequence |
| // |
| Opnd *helperArgs[] = { (Opnd *)src1, (Opnd *)src2 }; |
| |
| uint64 address = (uint64) remF4; |
| Opnd *helperAddress = opndManager->newImm(address); |
| |
| directCall(2, helperArgs, dst, helperAddress, p0); |
| } |
| } |
| |
| //----------------------------------------------------------------------------// |
| // create new inst and add it in current node |
| //----------------------------------------------------------------------------// |
| |
| void IpfInstCodeSelector::addInst(Inst *inst) { |
| |
| IPF_LOG << " " << IrPrinter::toString(inst) << endl; |
| node.addInst(inst); |
| } |
| |
| //----------------------------------------------------------------------------// |
| |
| Inst& IpfInstCodeSelector::addNewInst(InstCode instCode, |
| CG_OpndHandle *op1, |
| CG_OpndHandle *op2, |
| CG_OpndHandle *op3, |
| CG_OpndHandle *op4, |
| CG_OpndHandle *op5, |
| CG_OpndHandle *op6) { |
| |
| Inst* inst = new(mm) Inst(mm, instCode, (Opnd *)op1, (Opnd *)op2, (Opnd *)op3, |
| (Opnd *)op4, (Opnd *)op5, (Opnd *)op6); |
| addInst(inst); |
| return *inst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| |
| Inst& IpfInstCodeSelector::addNewInst(InstCode instCode, |
| Completer comp1, |
| CG_OpndHandle *op1, |
| CG_OpndHandle *op2, |
| CG_OpndHandle *op3, |
| CG_OpndHandle *op4, |
| CG_OpndHandle *op5, |
| CG_OpndHandle *op6) { |
| |
| Inst* inst = new(mm) Inst(mm, instCode, comp1, (Opnd *)op1, (Opnd *)op2, (Opnd *)op3, |
| (Opnd *)op4, (Opnd *)op5, (Opnd *)op6); |
| addInst(inst); |
| return *inst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| |
| Inst& IpfInstCodeSelector::addNewInst(InstCode instCode, |
| Completer comp1, |
| Completer comp2, |
| CG_OpndHandle *op1, |
| CG_OpndHandle *op2, |
| CG_OpndHandle *op3, |
| CG_OpndHandle *op4, |
| CG_OpndHandle *op5, |
| CG_OpndHandle *op6) { |
| |
| Inst* inst = new(mm) Inst(mm, instCode, comp1, comp2, (Opnd *)op1, (Opnd *)op2, (Opnd *)op3, |
| (Opnd *)op4, (Opnd *)op5, (Opnd *)op6); |
| addInst(inst); |
| return *inst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| |
| Inst& IpfInstCodeSelector::addNewInst(InstCode instCode, |
| Completer comp1, |
| Completer comp2, |
| Completer comp3, |
| CG_OpndHandle *op1, |
| CG_OpndHandle *op2, |
| CG_OpndHandle *op3, |
| CG_OpndHandle *op4, |
| CG_OpndHandle *op5, |
| CG_OpndHandle *op6) { |
| |
| Inst* inst = new(mm) Inst(mm, instCode, comp1, comp2, comp3, (Opnd *)op1, (Opnd *)op2, (Opnd *)op3, |
| (Opnd *)op4, (Opnd *)op5, (Opnd *)op6); |
| addInst(inst); |
| return *inst; |
| } |
| |
| //----------------------------------------------------------------------------// |
| // convertors from HLO to CG types |
| //----------------------------------------------------------------------------// |
| |
| DataKind IpfInstCodeSelector::toDataKind(Type::Tag tag) { |
| |
| switch(tag) { |
| case Type::Boolean : return DATA_U8; |
| case Type::Char : return DATA_U16; |
| case Type::Int8 : return DATA_I8; |
| case Type::Int16 : return DATA_I16; |
| case Type::Int32 : return DATA_I32; |
| case Type::Int64 : return DATA_I64; |
| case Type::UInt8 : return DATA_U8; |
| case Type::UInt16 : return DATA_U16; |
| case Type::UInt32 : return DATA_U32; |
| case Type::UInt64 : return DATA_U64; |
| case Type::IntPtr : return DATA_U64; |
| case Type::VTablePtr : return DATA_U64; |
| case Type::Single : return DATA_S; |
| case Type::Double : return DATA_D; |
| case Type::Float : return DATA_F; |
| case Type::Array : return DATA_BASE; |
| case Type::Object : return DATA_BASE; |
| case Type::NullObject : return DATA_BASE; |
| case Type::SystemClass : return DATA_BASE; |
| case Type::SystemObject : return DATA_BASE; |
| case Type::SystemString : return DATA_BASE; |
| case Type::ManagedPtr : return DATA_MPTR; |
| case Type::Tau : return DATA_INVALID; |
| case Type::CompressedSystemClass : |
| case Type::CompressedSystemString : |
| case Type::CompressedSystemObject : |
| case Type::CompressedObject : |
| case Type::CompressedArray : return DATA_U32; |
| default : IPF_ERR << "unexpected tag " << Type::tag2str(tag) << endl; |
| } |
| return DATA_INVALID; |
| } |
| |
| //----------------------------------------------------------------------------// |
| |
| OpndKind IpfInstCodeSelector::toOpndKind(Type::Tag tag) { |
| |
| switch(tag) { |
| case Type::Array : return OPND_G_REG; |
| case Type::Object : return OPND_G_REG; |
| case Type::NullObject : return OPND_G_REG; |
| case Type::SystemObject : return OPND_G_REG; |
| case Type::SystemClass : return OPND_G_REG; |
| case Type::Boolean : return OPND_G_REG; |
| case Type::Char : return OPND_G_REG; |
| case Type::Int8 : return OPND_G_REG; |
| case Type::Int16 : return OPND_G_REG; |
| case Type::Int32 : return OPND_G_REG; |
| case Type::Int64 : return OPND_G_REG; |
| case Type::UInt8 : return OPND_G_REG; |
| case Type::UInt16 : return OPND_G_REG; |
| case Type::UInt32 : return OPND_G_REG; |
| case Type::UInt64 : return OPND_G_REG; |
| case Type::Single : return OPND_F_REG; |
| case Type::Double : return OPND_F_REG; |
| case Type::Float : return OPND_F_REG; |
| case Type::IntPtr : return OPND_G_REG; |
| case Type::ManagedPtr : return OPND_G_REG; |
| case Type::VTablePtr : return OPND_G_REG; |
| case Type::SystemString : return OPND_G_REG; |
| case Type::Tau : return OPND_INVALID; |
| default : IPF_ERR << "unexpected tag " << Type::tag2str(tag) << endl; |
| } |
| return OPND_INVALID; |
| } |
| |
| //----------------------------------------------------------------------------// |
| |
| DataKind IpfInstCodeSelector::toDataKind(IntegerOp::Types type) { |
| |
| switch(type) { |
| case IntegerOp::I4 : return DATA_I32; |
| case IntegerOp::I8 : return DATA_I64; |
| case IntegerOp::I : return DATA_U64; |
| default : IPF_ERR << "unexpected type " << type << endl; |
| } |
| return DATA_INVALID; |
| } |
| |
| //----------------------------------------------------------------------------// |
| |
| DataKind IpfInstCodeSelector::toDataKind(NegOp::Types type) { |
| |
| switch (type) { |
| case NegOp::F : return DATA_F; |
| case NegOp::D : return DATA_D; |
| case NegOp::S : return DATA_S; |
| case NegOp::I4 : return DATA_I32; |
| case NegOp::I : |
| case NegOp::I8 : return DATA_I64; |
| default : IPF_ERR << "unexpected type " << type << endl; |
| } |
| return DATA_INVALID; |
| } |
| |
| //----------------------------------------------------------------------------// |
| |
| OpndKind IpfInstCodeSelector::toOpndKind(NegOp::Types type) { |
| |
| switch (type) { |
| case NegOp::F : |
| case NegOp::D : |
| case NegOp::S : return OPND_F_REG; |
| case NegOp::I4 : |
| case NegOp::I : |
| case NegOp::I8 : return OPND_G_REG; |
| default : IPF_ERR << "unexpected type " << type << endl; |
| } |
| return OPND_INVALID; |
| } |
| |
| //----------------------------------------------------------------------------// |
| |
| DataKind IpfInstCodeSelector::toDataKind(ArithmeticOp::Types type) { |
| |
| switch (type) { |
| case ArithmeticOp::F : return DATA_F; |
| case ArithmeticOp::D : return DATA_D; |
| case ArithmeticOp::S : return DATA_S; |
| case ArithmeticOp::I4 : return DATA_I32; |
| case ArithmeticOp::I8 : return DATA_I64; |
| case ArithmeticOp::I : return DATA_I64; |
| default : IPF_ERR << "unexpected type " << type << endl; |
| } |
| return DATA_INVALID; |
| } |
| |
| //----------------------------------------------------------------------------// |
| |
| OpndKind IpfInstCodeSelector::toOpndKind(ArithmeticOp::Types type) { |
| |
| switch(type) { |
| case ArithmeticOp::F : |
| case ArithmeticOp::D : |
| case ArithmeticOp::S : return OPND_F_REG; |
| case ArithmeticOp::I4 : |
| case ArithmeticOp::I8 : |
| case ArithmeticOp::I : return OPND_G_REG; |
| default : IPF_ERR << "unexpected type " << type << endl; |
| } |
| return OPND_INVALID; |
| } |
| |
| //----------------------------------------------------------------------------// |
| |
| DataKind IpfInstCodeSelector::toDataKind(RefArithmeticOp::Types type) { |
| |
| switch(type) { |
| case RefArithmeticOp::I4 : return DATA_I32; |
| case RefArithmeticOp::I : return DATA_I64; |
| default : IPF_ERR << "unexpected type " << type << endl; |
| } |
| return DATA_INVALID; |
| } |
| |
| //----------------------------------------------------------------------------// |
| |
| DataKind IpfInstCodeSelector::toDataKind(ConvertToIntOp::Types type, bool isSigned) { |
| |
| switch(type) { |
| case ConvertToIntOp::I1 : return isSigned ? DATA_I8 : DATA_U8; |
| case ConvertToIntOp::I2 : return isSigned ? DATA_I16 : DATA_U16; |
| case ConvertToIntOp::I : |
| case ConvertToIntOp::I4 : return isSigned ? DATA_I32 : DATA_U32; |
| case ConvertToIntOp::I8 : return isSigned ? DATA_I64 : DATA_U64; |
| default : IPF_ERR << "unexpected type " << type << endl; |
| } |
| return DATA_INVALID; |
| } |
| |
| //----------------------------------------------------------------------------// |
| |
| OpndKind IpfInstCodeSelector::toOpndKind(DivOp::Types type) { |
| |
| switch(type) { |
| case DivOp::I4 : |
| case DivOp::U4 : |
| case DivOp::I : |
| case DivOp::I8 : |
| case DivOp::U : |
| case DivOp::U8 : return OPND_G_REG; |
| case DivOp::F : |
| case DivOp::S : |
| case DivOp::D : return OPND_F_REG; |
| default : IPF_ERR << "unexpected type " << type << endl; |
| } |
| return OPND_INVALID; |
| } |
| |
| //----------------------------------------------------------------------------// |
| |
| DataKind IpfInstCodeSelector::toDataKind(DivOp::Types type) { |
| |
| switch(type) { |
| case DivOp::I4 : return DATA_I32; |
| case DivOp::U4 : return DATA_U32; |
| case DivOp::I : |
| case DivOp::I8 : return DATA_I64; |
| case DivOp::U : |
| case DivOp::U8 : return DATA_U64; |
| case DivOp::F : return DATA_F; |
| case DivOp::S : return DATA_S; |
| case DivOp::D : return DATA_D; |
| default : IPF_ERR << "unexpected type " << type << endl; |
| } |
| return DATA_INVALID; |
| } |
| |
| //----------------------------------------------------------------------------// |
| |
| InstCode IpfInstCodeSelector::toInstCmp(CompareOp::Types type) { |
| |
| switch(type) { |
| case CompareOp::I4 : return INST_CMP4; |
| case CompareOp::I8 : |
| case CompareOp::I : |
| case CompareOp::Ref : |
| case CompareOp::CompRef : return INST_CMP; |
| case CompareOp::F : |
| case CompareOp::S : |
| case CompareOp::D : return INST_FCMP; |
| default : IPF_ERR << "unexpected type " << type << endl; |
| } |
| return INST_INVALID; |
| } |
| |
| //----------------------------------------------------------------------------// |
| |
| InstCode IpfInstCodeSelector::toInstCmp(CompareZeroOp::Types type) { |
| |
| switch(type) { |
| case CompareZeroOp::I4 : return INST_CMP4; |
| case CompareZeroOp::I8 : |
| case CompareZeroOp::I : |
| case CompareZeroOp::Ref : return INST_CMP; |
| case CompareZeroOp::CompRef : return INST_CMP4; |
| default : IPF_ERR << "unexpected type " << type << endl; |
| } |
| return INST_INVALID; |
| } |
| |
| //----------------------------------------------------------------------------// |
| |
| Completer IpfInstCodeSelector::toCmpltCrel(CompareOp::Operators cmpOp, bool isFloating) { |
| |
| if (isFloating) { |
| switch (cmpOp) { |
| case CompareOp::Eq : return CMPLT_FCMP_FREL_EQ; |
| case CompareOp::Ne : return CMPLT_FCMP_FREL_NEQ; |
| case CompareOp::Gt : return CMPLT_FCMP_FREL_GT; |
| case CompareOp::Gtu : return CMPLT_FCMP_FREL_NLE; |
| case CompareOp::Ge : return CMPLT_FCMP_FREL_GE; |
| case CompareOp::Geu : return CMPLT_FCMP_FREL_NLT; |
| default : IPF_ERR << "unexpected type " << cmpOp << endl; |
| } |
| } else { |
| switch (cmpOp) { |
| case CompareOp::Eq : return CMPLT_CMP_CREL_EQ; |
| case CompareOp::Ne : return CMPLT_CMP_CREL_NE; |
| case CompareOp::Gt : return CMPLT_CMP_CREL_GT; |
| case CompareOp::Gtu : return CMPLT_CMP_CREL_GTU; |
| case CompareOp::Ge : return CMPLT_CMP_CREL_GE; |
| case CompareOp::Geu : return CMPLT_CMP_CREL_GEU; |
| default : IPF_ERR << "unexpected type " << cmpOp << endl; |
| } |
| } |
| |
| return CMPLT_INVALID; |
| } |
| |
| //----------------------------------------------------------------------------// |
| |
| Completer IpfInstCodeSelector::toCmpltSz(DataKind dataKind) { |
| |
| switch(dataKind) { |
| case DATA_I8 : |
| case DATA_U8 : return CMPLT_SZ_1; |
| case DATA_I16 : |
| case DATA_U16 : return CMPLT_SZ_2; |
| case DATA_I32 : |
| case DATA_U32 : return CMPLT_SZ_4; |
| case DATA_I64 : |
| case DATA_U64 : |
| case DATA_BASE : |
| case DATA_MPTR : return CMPLT_SZ_8; |
| case DATA_S : return CMPLT_FSZ_S; |
| case DATA_D : return CMPLT_FSZ_D; |
| case DATA_F : return CMPLT_FSZ_E; |
| default : IPF_ERR << "unexpected dataKind " << dataKind << endl; |
| } |
| return CMPLT_INVALID; |
| } |
| |
| } //namespace IPF |
| } //namespace Jitrino |