| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /** |
| * @author Intel, Pavel A. Ozhdikhin |
| */ |
| |
| #include "MemoryManager.h" |
| #include "IRBuilder.h" |
| #include "Inst.h" |
| #include "CSEHash.h" |
| #include "Log.h" |
| #include "irmanager.h" |
| #include "CompilationContext.h" |
| |
| namespace Jitrino { |
| |
| |
| #if defined(_MSC_VER) && !defined (__ICL) && !defined (__GNUC__) |
| #pragma warning(disable : 4355) |
| #endif |
| |
| static const char* help = \ |
| " expansion flags:\n"\ |
| " expandMemAddrs[={ON|off}]\n"\ |
| " expandElemAddrs[={ON|off}]\n"\ |
| " expandCallAddrs[={on|OFF}]\n"\ |
| " expandVirtualCallAddrs[={ON|off}]\n"\ |
| " expandNullChecks[={ON|off}]\n"\ |
| " expandElemTypeChecks[={ON|off}]\n"\ |
| " translation-time optimizations:\n"\ |
| " doCSE[={ON|off}]\n"\ |
| " doSimplify[={ON|off}]\n"\ |
| " suppressCheckBounds[={on|OFF}] - omit all bounds checks\n"\ |
| " insertMethodLabels[={on|OFF}]\n"\ |
| " compressedReferences[={on|OFF}] - force compressed references\n"; |
| |
| |
| static ActionFactory<IRBuilder, IRBuilderAction> _irbuilder(IRBUILDER_ACTION_NAME, help); |
| |
| |
| class IRBuilderSimplifier : public Simplifier { |
| public: |
| IRBuilderSimplifier(IRBuilder& irb) |
| : Simplifier(*irb.getIRManager(), false), irBuilder(irb) |
| {} |
| protected: |
| // numeric |
| virtual Inst* genAdd(Type* type, Modifier mod, Opnd* src1, Opnd* src2){ |
| return irBuilder.genAdd(type, mod, src1, src2)->getInst(); |
| } |
| virtual Inst* genSub(Type* type, Modifier mod, Opnd* src1, Opnd* src2) { |
| return irBuilder.genSub(type, mod, src1, src2)->getInst(); |
| } |
| virtual Inst* genNeg(Type* type, Opnd* src) { |
| return irBuilder.genNeg(type, src)->getInst(); |
| } |
| virtual Inst* genMul(Type* type, Modifier mod, Opnd* src1, Opnd* src2){ |
| return irBuilder.genMul(type, mod, src1, src2)->getInst(); |
| } |
| virtual Inst* genMulHi(Type* type, Modifier mod, Opnd* src1, Opnd* src2){ |
| return irBuilder.genMulHi(type, mod, src1, src2)->getInst(); |
| } |
| virtual Inst* genMin(Type* type, Opnd* src1, Opnd* src2){ |
| return irBuilder.genMin(type, src1, src2)->getInst(); |
| } |
| virtual Inst* genMax(Type* type, Opnd* src1, Opnd* src2){ |
| return irBuilder.genMax(type, src1, src2)->getInst(); |
| } |
| virtual Inst* genAbs(Type* type, Opnd* src1){ |
| return irBuilder.genAbs(type, src1)->getInst(); |
| } |
| // bitwise |
| virtual Inst* genAnd(Type* type, Opnd* src1, Opnd* src2){ |
| return irBuilder.genAnd(type, src1, src2)->getInst(); |
| } |
| virtual Inst* genOr(Type* type, Opnd* src1, Opnd* src2){ |
| return irBuilder.genOr(type, src1, src2)->getInst(); |
| } |
| virtual Inst* genXor(Type* type, Opnd* src1, Opnd* src2){ |
| return irBuilder.genXor(type, src1, src2)->getInst(); |
| } |
| virtual Inst* genNot(Type* type, Opnd* src1){ |
| return irBuilder.genNot(type, src1)->getInst(); |
| } |
| virtual Inst* genSelect(Type* type, Opnd* src1, Opnd* src2, Opnd* src3){ |
| return irBuilder.genSelect(type, src1, src2, src3)->getInst(); |
| } |
| // conversion |
| virtual Inst* genConv(Type* dstType, Type::Tag toType, Modifier ovfMod, Opnd* src){ |
| return irBuilder.genConv(dstType, toType, ovfMod, src)->getInst(); |
| } |
| |
| virtual Inst* genConvZE(Type* dstType, Type::Tag toType, Modifier ovfMod, Opnd* src){ |
| return irBuilder.genConvZE(dstType, toType, ovfMod, src)->getInst(); |
| } |
| |
| virtual Inst* genConvUnmanaged(Type* dstType, Type::Tag toType, Modifier ovfMod, Opnd* src){ |
| return irBuilder.genConvUnmanaged(dstType, toType, ovfMod, src)->getInst(); |
| } |
| |
| // shifts |
| virtual Inst* genShladd(Type* type, Opnd* src1, Opnd* src2, Opnd *src3){ |
| return irBuilder.genShladd(type, src1, src2, src3)->getInst(); |
| } |
| virtual Inst* genShl(Type* type, Modifier smmod, Opnd* src1, Opnd* src2){ |
| return irBuilder.genShl(type, smmod, src1, src2)->getInst(); |
| } |
| virtual Inst* genShr(Type* type, Modifier mods, Opnd* src1, Opnd* src2){ |
| return irBuilder.genShr(type, mods, src1, src2)->getInst(); |
| } |
| // comparison |
| virtual Inst* genCmp(Type* type, Type::Tag insttype, ComparisonModifier mod, Opnd* src1, Opnd* src2){ |
| return irBuilder.genCmp(type, insttype, mod, src1, src2)->getInst(); |
| } |
| // control flow |
| virtual void genJump(LabelInst* label) { |
| irBuilder.genJump(label); |
| } |
| virtual void genBranch(Type::Tag instType, ComparisonModifier mod, LabelInst* label, Opnd* src1, Opnd* src2) { |
| irBuilder.genBranch(instType, mod, label, src1, src2); |
| } |
| virtual void genBranch(Type::Tag instType, ComparisonModifier mod, LabelInst* label, Opnd* src1) { |
| irBuilder.genBranch(instType, mod, label, src1); |
| } |
| virtual Inst* genDirectCall(MethodDesc* methodDesc,Type* returnType,Opnd* tauNullCheckedFirstArg, |
| Opnd* tauTypesChecked,U_32 numArgs,Opnd* args[]) |
| { |
| irBuilder.genDirectCall(methodDesc, returnType, tauNullCheckedFirstArg, tauTypesChecked, numArgs, args); |
| return (Inst*)irBuilder.getCurrentLabel()->getNode()->getLastInst(); |
| } |
| // load, store & mov |
| virtual Inst* genLdConstant(I_32 val) { |
| return irBuilder.genLdConstant(val)->getInst(); |
| } |
| virtual Inst* genLdConstant(int64 val) { |
| return irBuilder.genLdConstant(val)->getInst(); |
| } |
| virtual Inst* genLdConstant(float val) { |
| return irBuilder.genLdConstant(val)->getInst(); |
| } |
| virtual Inst* genLdConstant(double val) { |
| return irBuilder.genLdConstant(val)->getInst(); |
| } |
| virtual Inst* genLdConstant(Type *type, ConstInst::ConstValue val) { |
| return irBuilder.genLdConstant(type, val)->getInst(); |
| } |
| virtual Inst* genTauLdInd(Modifier mod, Type* dstType, Type::Tag ldType, Opnd* src, |
| Opnd *tauNonNullBase, Opnd *tauAddressInRange) |
| { |
| return irBuilder.genTauLdInd(mod, dstType, ldType, src, tauNonNullBase, tauAddressInRange)->getInst(); |
| } |
| |
| virtual Inst* genLdRef(Modifier mod, Type* dstType, U_32 token, MethodDesc *enclosingMethod) { |
| return irBuilder.genLdRef(mod, dstType, token, enclosingMethod)->getInst(); |
| } |
| virtual Inst* genLdFunAddrSlot(MethodDesc* methodDesc) { |
| return irBuilder.genLdFunAddrSlot(methodDesc)->getInst(); |
| } |
| virtual Inst* genGetVTableAddr(ObjectType* type) { |
| return irBuilder.genGetVTable(type)->getInst(); |
| } |
| // compressed references |
| virtual Inst* genCompressRef(Opnd *uncompref){ |
| return irBuilder.genCompressRef(uncompref)->getInst(); |
| } |
| virtual Inst* genUncompressRef(Opnd *compref){ |
| return irBuilder.genUncompressRef(compref)->getInst(); |
| } |
| virtual Inst *genLdFieldOffsetPlusHeapbase(FieldDesc* fd) { |
| return irBuilder.genLdFieldOffsetPlusHeapbase(fd)->getInst(); |
| } |
| virtual Inst *genLdArrayBaseOffsetPlusHeapbase(Type *elemType) { |
| return irBuilder.genLdArrayBaseOffsetPlusHeapbase(elemType)->getInst(); |
| } |
| virtual Inst *genLdArrayLenOffsetPlusHeapbase(Type *elemType) { |
| return irBuilder.genLdArrayLenOffsetPlusHeapbase(elemType)->getInst(); |
| } |
| virtual Inst *genAddOffsetPlusHeapbase(Type *ptrType, Opnd *compRef, Opnd *offsetPlusHeapbase) { |
| return irBuilder.genAddOffsetPlusHeapbase(ptrType, compRef, offsetPlusHeapbase)->getInst(); |
| } |
| virtual Inst *genTauSafe() { |
| return irBuilder.genTauSafe()->getInst(); |
| } |
| virtual Inst *genTauMethodSafe() { |
| return irBuilder.genTauMethodSafe()->getInst(); |
| } |
| virtual Inst *genTauUnsafe() { |
| return irBuilder.genTauUnsafe()->getInst(); |
| } |
| virtual Inst* genTauStaticCast(Opnd *src, Opnd *tauCheckedCast, Type *castType) { |
| return irBuilder.genTauStaticCast(src, tauCheckedCast, castType)->getInst(); |
| } |
| virtual Inst* genTauHasType(Opnd *src, Type *castType) { |
| return irBuilder.genTauHasType(src, castType)->getInst(); |
| } |
| virtual Inst* genTauHasExactType(Opnd *src, Type *castType) { |
| return irBuilder.genTauHasExactType(src, castType)->getInst(); |
| } |
| virtual Inst* genTauIsNonNull(Opnd *src) { |
| return irBuilder.genTauIsNonNull(src)->getInst(); |
| } |
| // helper for store simplification, builds/finds simpler src, possibly |
| // modifies typetag or store modifier. |
| virtual Opnd* simplifyStoreSrc(Opnd *src, Type::Tag &typetag, Modifier &mod, bool compressRef) { |
| return 0; |
| } |
| virtual void foldBranch(BranchInst* br, bool isTaken) { |
| assert(0); |
| } |
| virtual void foldSwitch(SwitchInst* sw, U_32 index) { |
| assert(0); |
| } |
| virtual void eliminateCheck(Inst* checkInst, bool alwaysThrows) { |
| assert(0); |
| } |
| virtual void genThrowSystemException(CompilationInterface::SystemExceptionId id) { |
| irBuilder.genThrowSystemException(id); |
| } |
| private: |
| IRBuilder& irBuilder; |
| }; |
| |
| void IRBuilderAction::init() { |
| readFlags(); |
| } |
| |
| void IRBuilderAction::readFlags() { |
| // IRBuilder expansion flags |
| // |
| irBuilderFlags.expandMemAddrs = getBoolArg("expandMemAddrs", true); |
| irBuilderFlags.expandElemAddrs = getBoolArg("expandElemAddrs", true); |
| irBuilderFlags.expandCallAddrs = getBoolArg("expandCallAddrs", false); |
| irBuilderFlags.expandVirtualCallAddrs = getBoolArg("expandVirtualCallAddrs", true); |
| irBuilderFlags.expandNullChecks = getBoolArg("expandNullChecks", true); |
| irBuilderFlags.expandElemTypeChecks = getBoolArg("expandElemTypeChecks", true); |
| |
| // |
| // IRBuilder translation-time optimizations |
| // |
| irBuilderFlags.doCSE = getBoolArg("doCSE", true); |
| irBuilderFlags.doSimplify = getBoolArg("doSimplify", true); |
| |
| irBuilderFlags.suppressCheckBounds = getBoolArg("suppressCheckBounds", false); |
| |
| irBuilderFlags.insertMethodLabels = getBoolArg("insertMethodLabels", true); |
| irBuilderFlags.compressedReferences = getBoolArg("compressedReferences", false); |
| |
| irBuilderFlags.genMinMaxAbs = getBoolArg("genMinMaxAbs", false); |
| irBuilderFlags.genFMinMaxAbs = getBoolArg("genFMinMaxAbs", false); |
| |
| irBuilderFlags.useNewTypeSystem = getBoolArg("useNewTypeSystem", false); |
| } |
| |
| |
| |
| |
| IRBuilder::IRBuilder() : |
| irManager(NULL), |
| opndManager(NULL), |
| typeManager(NULL), |
| instFactory(NULL), |
| flowGraph(NULL), |
| translatorFlags(NULL), |
| currentLabel(NULL), |
| cseHashTable(NULL), |
| simplifier(NULL), |
| tauMethodSafeOpnd(NULL), |
| offset(0) |
| { |
| |
| } |
| |
| void IRBuilder::init(IRManager* irm, TranslatorFlags* traFlags, MemoryManager& tmpMM) { |
| IRBuilderAction* myAction = (IRBuilderAction*)getAction(); |
| irBuilderFlags = myAction->getFlags(); //copy of flags |
| |
| irManager=irm; |
| opndManager=&irm->getOpndManager(); |
| typeManager = &irm->getTypeManager(); |
| instFactory = &irm->getInstFactory(); |
| flowGraph = &irm->getFlowGraph(); |
| translatorFlags = traFlags; |
| MemoryManager& mm = irm->getMemoryManager(); |
| cseHashTable = new (tmpMM) CSEHashTable(mm); |
| |
| simplifier = new (mm) IRBuilderSimplifier(*this); |
| |
| CompilationInterface* ci = getCompilationContext()->getVMCompilationInterface(); |
| irBuilderFlags.insertWriteBarriers = ci->needWriteBarriers(); |
| irBuilderFlags.compressedReferences = irBuilderFlags.compressedReferences || VMInterface::areReferencesCompressed(); |
| } |
| |
| |
| void IRBuilder::invalid() { |
| Log::out() << " !!!! ---- IRBuilder::invalid ---- !!!! " << ::std::endl; |
| assert(0); |
| } |
| |
| void IRBuilder::updateCurrentLabelBcOffset() { |
| assert(currentLabel!=NULL); |
| if (currentLabel->getBCOffset()==ILLEGAL_BC_MAPPING_VALUE) { |
| assert(currentLabel->getNode() == NULL || currentLabel->getNode()->isEmpty()); |
| currentLabel->setBCOffset((uint16)offset); |
| } |
| } |
| |
| |
| Inst* IRBuilder::appendInst(Inst* inst) { |
| updateCurrentLabelBcOffset(); |
| assert(currentLabel->getBCOffset()!=ILLEGAL_BC_MAPPING_VALUE); |
| |
| inst->setBCOffset((uint16)offset); |
| Node* node = currentLabel->getNode(); |
| |
| node->appendInst(inst); |
| if(Log::isEnabled()) { |
| inst->print(Log::out()); |
| Log::out() << std::endl; |
| Log::out().flush(); |
| } |
| return inst; |
| } |
| |
| void IRBuilder::killCSE() { |
| cseHashTable->kill(); |
| } |
| |
| void IRBuilder::genLabel(LabelInst* labelInst) { |
| cseHashTable->kill(); |
| currentLabel = labelInst; |
| updateCurrentLabelBcOffset(); |
| |
| if(Log::isEnabled()) { |
| currentLabel->print(Log::out()); |
| Log::out() << std::endl; |
| Log::out().flush(); |
| } |
| } |
| |
| void IRBuilder::genFallThroughLabel(LabelInst* labelInst) { |
| currentLabel = labelInst; |
| updateCurrentLabelBcOffset(); |
| |
| if(Log::isEnabled()) { |
| currentLabel->print(Log::out()); |
| Log::out() << std::endl; |
| Log::out().flush(); |
| } |
| } |
| |
| LabelInst* IRBuilder::createLabel() { |
| currentLabel = (LabelInst*)instFactory->makeLabel(); |
| updateCurrentLabelBcOffset(); |
| return currentLabel; |
| } |
| |
| void IRBuilder::createLabels(U_32 numLabels, LabelInst** labels) { |
| for (U_32 i=0; i<numLabels; i++) { |
| labels[i] = (LabelInst*)instFactory->makeLabel(); |
| } |
| } |
| |
| LabelInst* IRBuilder::genMethodEntryLabel(MethodDesc* methodDesc) { |
| currentLabel = instFactory->makeMethodEntryLabel(methodDesc); |
| currentLabel->setBCOffset(0); |
| |
| if(Log::isEnabled()) { |
| currentLabel->print(Log::out()); |
| Log::out() << std::endl; |
| Log::out().flush(); |
| } |
| return currentLabel; |
| } |
| |
| // compute instructions |
| Opnd* |
| IRBuilder::genAdd(Type* dstType, Modifier mod, Opnd* src1, Opnd* src2) { |
| src1 = propagateCopy(src1); |
| src2 = propagateCopy(src2); |
| Operation operation(Op_Add, dstType->tag, mod); |
| U_32 hashcode = operation.encodeForHashing(); |
| Opnd* dst = lookupHash(hashcode, src1, src2); |
| if (dst) return dst; |
| |
| if (irBuilderFlags.doSimplify) { |
| dst = simplifier->simplifyAdd(dstType, mod, src1, src2); |
| } |
| if (!dst) { |
| dst = createOpnd(dstType); |
| Inst *newi = instFactory->makeAdd(mod, dst, src1, src2); |
| appendInst(newi); |
| } |
| insertHash(hashcode, src1, src2, dst->getInst()); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genMul(Type* dstType, Modifier mod, Opnd* src1, Opnd* src2) { |
| src1 = propagateCopy(src1); |
| src2 = propagateCopy(src2); |
| Operation operation(Op_Mul, dstType->tag, mod); |
| U_32 hashcode = operation.encodeForHashing(); |
| Opnd* dst = lookupHash(hashcode, src1, src2); |
| if (dst) return dst; |
| |
| if (irBuilderFlags.doSimplify) { |
| dst = simplifier->simplifyMul(dstType, mod, src1, src2); |
| } |
| if (!dst) { |
| dst = createOpnd(dstType); |
| appendInst(instFactory->makeMul(mod, dst, src1, src2)); |
| } |
| insertHash(hashcode, src1, src2, dst->getInst()); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genSub(Type* dstType, Modifier mod, Opnd* src1, Opnd* src2) { |
| src1 = propagateCopy(src1); |
| src2 = propagateCopy(src2); |
| Operation operation(Op_Sub, dstType->tag, mod); |
| U_32 hashcode = operation.encodeForHashing(); |
| Opnd* dst = lookupHash(hashcode, src1, src2); |
| if (dst) return dst; |
| |
| if (irBuilderFlags.doSimplify) { |
| dst = simplifier->simplifySub(dstType, mod, src1, src2); |
| } |
| if (!dst) { |
| dst = createOpnd(dstType); |
| appendInst(instFactory->makeSub(mod, dst, src1, src2)); |
| } |
| insertHash(hashcode, src1, src2, dst->getInst()); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genDiv(Type* dstType, Modifier mod, Opnd* src1, Opnd* src2) { |
| src1 = propagateCopy(src1); |
| src2 = propagateCopy(src2); |
| Opnd *tauDivOk = 0; |
| if(src2->getType()->isInteger()) |
| tauDivOk = genTauCheckZero(src2); |
| else |
| tauDivOk = genTauSafe(); // safe by construction |
| Operation operation(Op_TauDiv, dstType->tag, mod); |
| U_32 hashcode = operation.encodeForHashing(); |
| Opnd* dst = lookupHash(hashcode, src1, src2); // tauDivOk is not needed in hash |
| if (dst) return dst; |
| |
| if (irBuilderFlags.doSimplify) { |
| dst = simplifier->simplifyTauDiv(dstType, mod, src1, src2, tauDivOk); |
| } |
| if (!dst) { |
| dst = createOpnd(dstType); |
| appendInst(instFactory->makeTauDiv(mod, dst, src1, src2, tauDivOk)); |
| } |
| insertHash(hashcode, src1, src2, dst->getInst()); // tauDivOk is not needed in hash |
| return dst; |
| } |
| |
| // |
| // for CLI: inserts a CheckDivOpnds before the divide |
| Opnd* |
| IRBuilder::genCliDiv(Type* dstType, Modifier mod, Opnd* src1, Opnd* src2) { |
| src1 = propagateCopy(src1); |
| src2 = propagateCopy(src2); |
| |
| Operation operation(Op_TauDiv, dstType->tag, mod); |
| U_32 hashcode = operation.encodeForHashing(); |
| Opnd* dst = lookupHash(hashcode, src1, src2); // tauDivOk is not needed in hash |
| if (dst) return dst; |
| |
| Opnd *tauDivOk = 0; |
| if(src2->getType()->isInteger()) { |
| if (mod.getSignedModifier() == SignedOp) { |
| // for CLI: if signed, insert a CheckDivOpnds before the divide |
| tauDivOk = genTauCheckDivOpnds(src1, src2); |
| } else { |
| // if unsigned, still need a zero check |
| tauDivOk = genTauCheckZero(src2); |
| } |
| } else { |
| tauDivOk = genTauSafe(); // safe by construction |
| } |
| if (irBuilderFlags.doSimplify) { |
| dst = simplifier->simplifyTauDiv(dstType, mod, src1, src2, tauDivOk); |
| } |
| if (!dst) { |
| dst = createOpnd(dstType); |
| appendInst(instFactory->makeTauDiv(mod, dst, src1, src2, tauDivOk)); |
| } |
| insertHash(hashcode, src1, src2, dst->getInst()); // tauDivOk is not needed in hash |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genRem(Type* dstType, Modifier mod, Opnd* src1, Opnd* src2) { |
| src1 = propagateCopy(src1); |
| src2 = propagateCopy(src2); |
| |
| Operation operation(Op_TauRem, dstType->tag, mod); |
| U_32 hashcode = operation.encodeForHashing(); |
| Opnd* dst = lookupHash(hashcode, src1, src2); // tauDivOk is not needed in hash |
| if (dst) return dst; |
| |
| |
| Opnd *tauDivOk = 0; |
| if(src2->getType()->isInteger()) |
| tauDivOk = genTauCheckZero(src2); |
| else |
| tauDivOk = genTauSafe(); // safe by construction |
| |
| if (irBuilderFlags.doSimplify) { |
| dst = simplifier->simplifyTauRem(dstType, mod, src1, src2, tauDivOk); |
| } |
| if (!dst) { |
| dst = createOpnd(dstType); |
| appendInst(instFactory->makeTauRem(mod, dst, src1, src2, tauDivOk)); |
| } |
| insertHash(hashcode, src1, src2, dst->getInst()); // tauDivOk is not needed in hash |
| return dst; |
| } |
| |
| // |
| // for CLI: inserts a CheckDivOpnds before the divide |
| // |
| Opnd* |
| IRBuilder::genCliRem(Type* dstType, Modifier mod, Opnd* src1, Opnd* src2) { |
| src1 = propagateCopy(src1); |
| src2 = propagateCopy(src2); |
| |
| Operation operation(Op_TauRem, dstType->tag, mod); |
| U_32 hashcode = operation.encodeForHashing(); |
| Opnd* dst = lookupHash(hashcode, src1, src2); // tauDivOk is not needed in hash |
| if (dst) return dst; |
| |
| |
| Opnd *tauDivOk = 0; |
| if (src2->getType()->isInteger()) |
| if (mod.getSignedModifier() == SignedOp) |
| // for CLI: if signed, insert a CheckDivOpnds before the divide |
| tauDivOk = genTauCheckDivOpnds(src1, src2); |
| else |
| // if unsigned, still need zero check |
| tauDivOk = genTauCheckZero(src2); |
| else |
| tauDivOk = genTauSafe(); // safe by construction |
| |
| if (irBuilderFlags.doSimplify) { |
| dst = simplifier->simplifyTauRem(dstType, mod, src1, src2, tauDivOk); |
| } |
| |
| if (!dst) { |
| dst = createOpnd(dstType); |
| appendInst(instFactory->makeTauRem(mod, dst, src1, src2, tauDivOk)); |
| } |
| insertHash(hashcode, src1, src2, dst->getInst()); // tauDivOk is not needed in hash |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genNeg(Type* dstType, Opnd* src) { |
| src = propagateCopy(src); |
| Operation operation(Op_Neg, dstType->tag, Modifier()); |
| U_32 hashcode = operation.encodeForHashing(); |
| Opnd* dst = lookupHash(hashcode, src); |
| if (dst) return dst; |
| |
| if (irBuilderFlags.doSimplify) { |
| dst = simplifier->simplifyNeg(dstType, src); |
| } |
| if (!dst) { |
| dst = createOpnd(dstType); |
| appendInst(instFactory->makeNeg(dst, src)); |
| } |
| insertHash(Op_Neg, src, dst->getInst()); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genMulHi(Type* dstType, Modifier mod, Opnd* src1, Opnd* src2) { |
| src1 = propagateCopy(src1); |
| src2 = propagateCopy(src2); |
| Operation operation(Op_MulHi, dstType->tag, mod); |
| U_32 hashcode = operation.encodeForHashing(); |
| Opnd* dst = lookupHash(hashcode, src1, src2); |
| if (dst) return dst; |
| |
| if (irBuilderFlags.doSimplify) { |
| dst = simplifier->simplifyMulHi(dstType, mod, src1, src2); |
| } |
| if (!dst) { |
| dst = createOpnd(dstType); |
| appendInst(instFactory->makeMulHi(mod, dst, src1, src2)); |
| } |
| insertHash(hashcode, src1, src2, dst->getInst()); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genMin(Type* dstType, Opnd* src1, Opnd* src2) { |
| if (irBuilderFlags.genMinMaxAbs && |
| (!dstType->isFloatingPoint() || irBuilderFlags.genFMinMaxAbs)) { |
| |
| src1 = propagateCopy(src1); |
| src2 = propagateCopy(src2); |
| |
| Operation operation(Op_Min, dstType->tag, Modifier()); |
| U_32 hashcode = operation.encodeForHashing(); |
| Opnd* dst = lookupHash(hashcode, src1, src2); |
| if (dst) return dst; |
| |
| if (irBuilderFlags.doSimplify) { |
| dst = simplifier->simplifyMin(dstType, src1, src2); |
| } |
| if (!dst) { |
| dst = createOpnd(dstType); |
| appendInst(instFactory->makeMin(dst, src1, src2)); |
| } |
| insertHash(hashcode, src1, src2, dst->getInst()); |
| return dst; |
| } else { |
| // hand-build it |
| |
| Type* cmpDstType = typeManager->getInt32Type(); |
| Type::Tag typeTag = dstType->tag; |
| switch (typeTag) { |
| case Type::Int32: |
| case Type::Int64: |
| { |
| Opnd *cmpRes = genCmp(cmpDstType, typeTag, |
| Cmp_GT, src2, src1); |
| Opnd *res = genSelect(dstType, cmpRes, |
| src1, src2); |
| return res; |
| } |
| case Type::Single: |
| case Type::Double: |
| { |
| // check for NaN |
| Opnd *src1IsNaN = genCmp(cmpDstType, typeTag, |
| Cmp_NE_Un, |
| src1, src1); |
| Opnd * zero = ((typeTag == Type::Single) |
| ? genLdConstant((float)0) |
| : genLdConstant((double)0)); |
| // we may have [+-]0.0, which can't be distinguished by cmp |
| Opnd *cmp2aRes = genCmp(cmpDstType, typeTag, |
| Cmp_EQ, src1, zero); |
| Opnd *cmp2bRes = genCmp(cmpDstType, typeTag, |
| Cmp_EQ, src2, zero); |
| Opnd *bothAreZero = genAnd(cmpDstType, |
| cmp2aRes, cmp2bRes); |
| // but this expression apparently gets correct min |
| Opnd *minOfZeros = |
| genNeg(dstType, |
| genSub(dstType, |
| Modifier(Overflow_None)| |
| Modifier(Exception_Never)|Modifier(Strict_No), |
| genNeg(dstType, src1), |
| src2)); |
| // otherwise, we can just use a simple min expression |
| Opnd *cmpRes = genCmp(cmpDstType, typeTag, |
| Cmp_GT, src2, src1); |
| Opnd *simpleMin = genSelect(dstType, cmpRes, |
| src1, src2); |
| Opnd *res = |
| genSelect(dstType, |
| src1IsNaN, |
| src1, |
| genSelect(dstType, |
| bothAreZero, |
| minOfZeros, |
| simpleMin)); |
| return res; |
| } |
| default: |
| break; |
| } |
| assert(0); |
| return 0; |
| } |
| } |
| |
| Opnd* |
| IRBuilder::genMax(Type* dstType, Opnd* src1, Opnd* src2) { |
| if (irBuilderFlags.genMinMaxAbs && |
| (!dstType->isFloatingPoint() || irBuilderFlags.genFMinMaxAbs)) { |
| src1 = propagateCopy(src1); |
| src2 = propagateCopy(src2); |
| Operation operation(Op_Max, dstType->tag, Modifier()); |
| U_32 hashcode = operation.encodeForHashing(); |
| Opnd* dst = lookupHash(hashcode, src1, src2); |
| if (dst) return dst; |
| |
| if (irBuilderFlags.doSimplify) { |
| dst = simplifier->simplifyMax(dstType, src1, src2); |
| } |
| if (!dst) { |
| dst = createOpnd(dstType); |
| appendInst(instFactory->makeMax(dst, src1, src2)); |
| } |
| insertHash(hashcode, src1, src2, dst->getInst()); |
| return dst; |
| } else { |
| Type::Tag typeTag = dstType->tag; |
| Type* cmpDstType = typeManager->getInt32Type(); |
| switch (typeTag) { |
| case Type::Int32: |
| case Type::Int64: |
| { |
| Opnd *cmpRes = genCmp(cmpDstType, typeTag, Cmp_GT, src1, src2); |
| Opnd *res = genSelect(dstType, cmpRes, src1, src2); |
| return res; |
| } |
| case Type::Single: |
| case Type::Double: |
| { |
| // check for NaN |
| Opnd *src1IsNaN = genCmp(cmpDstType, typeTag, |
| Cmp_NE_Un, src1, src1); |
| Opnd * zero = ((typeTag == Type::Single) |
| ? genLdConstant((float)0) |
| : genLdConstant((double)0)); |
| // we may have [+-]0.0, which can't be distinguished by cmp |
| Opnd *cmp2aRes = genCmp(cmpDstType, typeTag, Cmp_EQ, src1, zero); |
| Opnd *cmp2bRes = genCmp(cmpDstType, typeTag, Cmp_EQ, src2, zero); |
| Opnd *bothAreZero = genAnd(cmpDstType, cmp2aRes, cmp2bRes); |
| // but this expression apparently gets correct max |
| Opnd *maxOfZeros = genSub(dstType, |
| Modifier(Overflow_None)| |
| Modifier(Exception_Never)|Modifier(Strict_No), |
| src1, |
| genNeg(dstType, src2)); |
| Opnd *cmpRes = genCmp(cmpDstType, typeTag, |
| Cmp_GT, src1, src2); |
| Opnd *simpleMin = genSelect(dstType, cmpRes, |
| src1, src2); |
| Opnd *res = genSelect(dstType, |
| src1IsNaN, |
| src1, |
| genSelect(dstType, |
| bothAreZero, |
| maxOfZeros, |
| simpleMin)); |
| |
| return res; |
| } |
| default: |
| break; |
| } |
| assert(0); |
| return 0; |
| } |
| } |
| |
| Opnd* |
| IRBuilder::genAbs(Type* dstType, Opnd* src1) { |
| if (irBuilderFlags.genMinMaxAbs && |
| (!dstType->isFloatingPoint() || irBuilderFlags.genFMinMaxAbs)) { |
| |
| src1 = propagateCopy(src1); |
| Operation operation(Op_Abs, dstType->tag, Modifier()); |
| U_32 hashcode = operation.encodeForHashing(); |
| Opnd* dst = lookupHash(hashcode, src1); |
| if (dst) return dst; |
| |
| if (irBuilderFlags.doSimplify) { |
| dst = simplifier->simplifyAbs(dstType, src1); |
| } |
| if (!dst) { |
| dst = createOpnd(dstType); |
| appendInst(instFactory->makeAbs(dst, src1)); |
| } |
| insertHash(hashcode, src1, dst->getInst()); |
| return dst; |
| } else { |
| // hand-build it |
| |
| Type::Tag typeTag = src1->getType()->tag; |
| Type* cmpDstType = typeManager->getInt32Type(); |
| switch (typeTag) { |
| case Type::Int32: |
| case Type::Int64: |
| { |
| Opnd *zero = ((typeTag == Type::Int32) |
| ? genLdConstant((I_32)0) |
| : genLdConstant((int64)0)); |
| Opnd *cmpRes = genCmp(cmpDstType, typeTag, |
| Cmp_GT, zero, src1); |
| Opnd *negSrc = genNeg(dstType, src1); |
| Opnd *res = genSelect(dstType, cmpRes, negSrc, src1); |
| return res; |
| } |
| case Type::Single: |
| case Type::Double: |
| { |
| Opnd *zero = ((typeTag == Type::Single) |
| ? genLdConstant((float)0) |
| : genLdConstant((double)0)); |
| Opnd *cmpRes = genCmp(cmpDstType, typeTag, |
| Cmp_GTE, zero, src1); |
| Opnd *negSrc = genSub(dstType, |
| Modifier(Overflow_None)| |
| Modifier(Exception_Never)|Modifier(Strict_No), |
| zero, |
| src1); |
| Opnd *res = genSelect(dstType, cmpRes, negSrc, src1); |
| return res; |
| } |
| default: |
| break; |
| } |
| assert(0); |
| return 0; |
| } |
| } |
| |
| // bitwise instructions |
| Opnd* |
| IRBuilder::genAnd(Type* dstType, Opnd* src1, Opnd* src2) { |
| src1 = propagateCopy(src1); |
| src2 = propagateCopy(src2); |
| Opnd* dst = lookupHash(Op_And, src1, src2); |
| if (dst) return dst; |
| |
| if (irBuilderFlags.doSimplify) { |
| dst = simplifier->simplifyAnd(dstType, src1, src2); |
| } |
| if (!dst) { |
| dst = createOpnd(dstType); |
| appendInst(instFactory->makeAnd(dst, src1, src2)); |
| } |
| insertHash(Op_And, src1, src2, dst->getInst()); |
| return dst; |
| } |
| Opnd* |
| IRBuilder::genOr(Type* dstType, Opnd* src1, Opnd* src2) { |
| src1 = propagateCopy(src1); |
| src2 = propagateCopy(src2); |
| Opnd* dst = lookupHash(Op_Or, src1, src2); |
| if (dst) return dst; |
| |
| if (irBuilderFlags.doSimplify) { |
| dst = simplifier->simplifyOr(dstType, src1, src2); |
| } |
| if (!dst) { |
| dst = createOpnd(dstType); |
| appendInst(instFactory->makeOr(dst, src1, src2)); |
| } |
| insertHash(Op_Or, src1, src2, dst->getInst()); |
| return dst; |
| } |
| Opnd* |
| IRBuilder::genXor(Type* dstType, Opnd* src1, Opnd* src2) { |
| src1 = propagateCopy(src1); |
| src2 = propagateCopy(src2); |
| Opnd* dst = lookupHash(Op_Xor, src1, src2); |
| if (dst) return dst; |
| |
| if (irBuilderFlags.doSimplify) { |
| dst = simplifier->simplifyXor(dstType, src1, src2); |
| } |
| if (!dst) { |
| dst = createOpnd(dstType); |
| appendInst(instFactory->makeXor(dst, src1, src2)); |
| } |
| insertHash(Op_Xor, src1, src2, dst->getInst()); |
| return dst; |
| } |
| Opnd* |
| IRBuilder::genNot(Type* dstType, Opnd* src) { |
| src = propagateCopy(src); |
| Opnd* dst = lookupHash(Op_Not, src); |
| if (dst) return dst; |
| |
| if (irBuilderFlags.doSimplify) { |
| dst = simplifier->simplifyNot(dstType, src); |
| } |
| if (!dst) { |
| dst = createOpnd(dstType); |
| appendInst(instFactory->makeNot(dst, src)); |
| } |
| insertHash(Op_Not, src, dst->getInst()); |
| return dst; |
| } |
| |
| // selection |
| Opnd* |
| IRBuilder::genSelect(Type* dstType, Opnd* src1, Opnd* src2, Opnd* src3) { |
| src1 = propagateCopy(src1); |
| src2 = propagateCopy(src2); |
| src3 = propagateCopy(src3); |
| Opnd* dst = lookupHash(Op_Select, src1, src2, src3); |
| if (dst) return dst; |
| |
| if (irBuilderFlags.doSimplify) { |
| dst = simplifier->simplifySelect(dstType, src1, src2, src3); |
| } |
| if (!dst) { |
| dst = createOpnd(dstType); |
| appendInst(instFactory->makeSelect(dst, src1, src2, src3)); |
| } |
| insertHash(Op_Select, src1, src2, src3, dst->getInst()); |
| return dst; |
| } |
| |
| // Conversion |
| Opnd* |
| IRBuilder::genConv(Type* dstType, |
| Type::Tag toType, |
| Modifier ovfMod, |
| Opnd* src) |
| { |
| src = propagateCopy(src); |
| Operation operation(Op_Conv, toType, ovfMod); |
| U_32 hashcode = operation.encodeForHashing(); |
| Opnd* dst = lookupHash(hashcode, src->getId()); |
| if (dst) return dst; |
| |
| if (irBuilderFlags.doSimplify) { |
| dst = simplifier->simplifyConv(dstType, toType, ovfMod, src); |
| } |
| if (!dst) { |
| dst = createOpnd(dstType); |
| Inst* inst = instFactory->makeConv(ovfMod, toType, dst, src); |
| appendInst(inst); |
| } |
| insertHash(hashcode, src->getId(), dst->getInst()); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genConvUnmanaged(Type* dstType, |
| Type::Tag toType, |
| Modifier ovfMod, |
| Opnd* src) |
| { |
| assert((dstType->isUnmanagedPtr() && src->getType()->isObject()) |
| || (dstType->isObject() && src->getType()->isUnmanagedPtr())); |
| src = propagateCopy(src); |
| Operation operation(Op_ConvUnmanaged, toType, ovfMod); |
| U_32 hashcode = operation.encodeForHashing(); |
| Opnd* dst = lookupHash(hashcode, src->getId()); |
| if (dst) return dst; |
| |
| if (irBuilderFlags.doSimplify) { |
| dst = simplifier->simplifyConvUnmanaged(dstType, toType, ovfMod, src); |
| } |
| if (!dst) { |
| dst = createOpnd(dstType); |
| Inst* inst = instFactory->makeConvUnmanaged(ovfMod, toType, dst, src); |
| appendInst(inst); |
| } |
| |
| insertHash(hashcode, src->getId(), dst->getInst()); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genConvZE(Type* dstType, |
| Type::Tag toType, |
| Modifier ovfMod, |
| Opnd* src) |
| { |
| assert(src->getType()->isInteger() && (dstType->isInteger() || dstType->isUnmanagedPtr())); |
| src = propagateCopy(src); |
| Operation operation(Op_ConvZE, toType, ovfMod); |
| U_32 hashcode = operation.encodeForHashing(); |
| Opnd* dst = lookupHash(hashcode, src->getId()); |
| if (dst) return dst; |
| |
| if (irBuilderFlags.doSimplify) { |
| dst = simplifier->simplifyConvZE(dstType, toType, ovfMod, src); |
| } |
| if (!dst) { |
| dst = createOpnd(dstType); |
| Inst* inst = instFactory->makeConvZE(ovfMod, toType, dst, src); |
| appendInst(inst); |
| } |
| insertHash(hashcode, src->getId(), dst->getInst()); |
| return dst; |
| } |
| |
| // Shift |
| Opnd* |
| IRBuilder::genShladd(Type* dstType, |
| Opnd* value, |
| Opnd* shiftAmount, |
| Opnd* addTo) { |
| value = propagateCopy(value); |
| shiftAmount = propagateCopy(shiftAmount); |
| addTo = propagateCopy(addTo); |
| Opnd* dst = lookupHash(Op_Shladd, value, shiftAmount, addTo); |
| if (dst) return dst; |
| |
| if (irBuilderFlags.doSimplify) { |
| dst = simplifier->simplifyShladd(dstType, value, shiftAmount, addTo); |
| } |
| if (!dst) { |
| dst = createOpnd(dstType); |
| appendInst(instFactory->makeShladd(dst, value, shiftAmount, addTo)); |
| } |
| insertHash(Op_Shladd, value, shiftAmount, addTo, dst->getInst()); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genShl(Type* dstType, |
| Modifier mod, |
| Opnd* value, |
| Opnd* shiftAmount) { |
| value = propagateCopy(value); |
| shiftAmount = propagateCopy(shiftAmount); |
| |
| Operation operation(Op_Shladd, dstType->tag, mod); |
| U_32 hashcode = operation.encodeForHashing(); |
| Opnd* dst = lookupHash(hashcode, value, shiftAmount); |
| if (dst) return dst; |
| |
| if (irBuilderFlags.doSimplify) { |
| dst = simplifier->simplifyShl(dstType, mod, value, shiftAmount); |
| } |
| if (!dst) { |
| dst = createOpnd(dstType); |
| appendInst(instFactory->makeShl(mod, dst, value, shiftAmount)); |
| } |
| insertHash(hashcode, value, shiftAmount, dst->getInst()); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genShr(Type* dstType, |
| Modifier mods, |
| Opnd* value, |
| Opnd* shiftAmount) { |
| value = propagateCopy(value); |
| shiftAmount = propagateCopy(shiftAmount); |
| |
| Operation operation(Op_Shr, dstType->tag, mods); |
| U_32 hashcode = operation.encodeForHashing(); |
| Opnd* dst = lookupHash(hashcode, value, shiftAmount); |
| if (dst) return dst; |
| |
| if (irBuilderFlags.doSimplify) { |
| dst = simplifier->simplifyShr(dstType, mods, value, shiftAmount); |
| } |
| if (!dst) { |
| dst = createOpnd(dstType); |
| appendInst(instFactory->makeShr(mods, dst, value, shiftAmount)); |
| } |
| insertHash(hashcode, value, shiftAmount, dst->getInst()); |
| return dst; |
| } |
| |
| // Comparison |
| Opnd* |
| IRBuilder::genCmp(Type* dstType, |
| Type::Tag instType, // source type for inst |
| ComparisonModifier mod, |
| Opnd* src1, |
| Opnd* src2) { |
| src1 = propagateCopy(src1); |
| src2 = propagateCopy(src2); |
| |
| Operation operation(Op_Cmp, instType, mod); |
| U_32 hashcode = operation.encodeForHashing(); |
| Opnd* dst = lookupHash(hashcode, src1, src2); |
| if (dst) return dst; |
| |
| if (irBuilderFlags.doSimplify) { |
| dst = simplifier->simplifyCmp(dstType, instType, mod, src1, src2); |
| } |
| if (!dst) { |
| // result of comparison is always a 32-bit int |
| dst = createOpnd(dstType); |
| Inst *i = instFactory->makeCmp(mod, instType, dst, src1, src2); |
| appendInst(i); |
| } |
| insertHash(hashcode, src1, src2, dst->getInst()); |
| return dst; |
| } |
| |
| // 3-way Java-like Comparison |
| // effect is (src1 cmp src2) ? 1 : (src2 cmp src1) ? -1 : 0 |
| // For Float or Double args, if Cmp_GT_Un, then second compare is Cmp_GT, |
| // and vice versa, so that |
| // Cmp3(...,Cmp_GT_Un,src1,src2) -> 1 if src1 or src2 is NaN |
| // Cmp3(...,Cmp_GT,src1,src2) -> -1 if src1 or src2 is NaN |
| Opnd* |
| IRBuilder::genCmp3(Type* dstType, |
| Type::Tag instType, // source type for inst |
| ComparisonModifier mod, |
| Opnd* src1, |
| Opnd* src2) { |
| src1 = propagateCopy(src1); |
| src2 = propagateCopy(src2); |
| Operation operation(Op_Cmp3, instType, mod); |
| U_32 hashcode = operation.encodeForHashing(); |
| Opnd* dst = lookupHash(hashcode, src1, src2); |
| if (dst) return dst; |
| |
| if (irBuilderFlags.doSimplify) { |
| dst = simplifier->simplifyCmp3(dstType, instType, mod, |
| src1, src2); |
| } |
| if (!dst) { |
| // result of comparison is always a 32-bit int |
| dst = createOpnd(dstType); |
| Inst* i = instFactory->makeCmp3(mod, instType, dst, src1, src2); |
| appendInst(i); |
| } |
| insertHash(hashcode, src1, src2, dst->getInst()); |
| return dst; |
| } |
| |
| // Control flow |
| void |
| IRBuilder::genBranch(Type::Tag instType, |
| ComparisonModifier mod, |
| LabelInst* label, |
| Opnd* src1, |
| Opnd* src2) { |
| src1 = propagateCopy(src1); |
| src2 = propagateCopy(src2); |
| if (mod > Cmp_GTE_Un) |
| // bad modifier |
| invalid(); |
| if (irBuilderFlags.doSimplify) { |
| if (simplifier->simplifyBranch(instType, mod, label, src1, src2)) { |
| // simplified branch was emitted; |
| return; |
| } |
| } |
| appendInst(instFactory->makeBranch(mod, instType, src1, src2, label)); |
| } |
| |
| void |
| IRBuilder::genBranch(Type::Tag instType, |
| ComparisonModifier mod, |
| LabelInst* label, |
| Opnd* src) { |
| src = propagateCopy(src); |
| if (mod < Cmp_Zero) |
| // bad modifier |
| invalid(); |
| if (irBuilderFlags.doSimplify) { |
| if (simplifier->simplifyBranch(instType, mod, label, src)) { |
| // simplified branch was emitted; |
| return; |
| } |
| } |
| appendInst(instFactory->makeBranch(mod, instType, src, label)); |
| } |
| |
| |
| void |
| IRBuilder::genJump(LabelInst* label) { |
| appendInst(instFactory->makeJump(label)); |
| } |
| |
| void |
| IRBuilder::genJSR(LabelInst* label) { |
| appendInst(instFactory->makeJSR(label)); |
| } |
| |
| void |
| IRBuilder::genSwitch(U_32 nLabels, |
| LabelInst* labelInsts[], |
| LabelInst* defaultLabel, |
| Opnd* src) { |
| src = propagateCopy(src); |
| appendInst(instFactory->makeSwitch(src, nLabels, labelInsts, defaultLabel)); |
| } |
| |
| void |
| IRBuilder::genThrow(ThrowModifier mod, Opnd* exceptionObj) { |
| exceptionObj = propagateCopy(exceptionObj); |
| appendInst(instFactory->makeThrow(mod, exceptionObj)); |
| } |
| |
| void |
| IRBuilder::genPseudoThrow() { |
| appendInst(instFactory->makePseudoThrow()); |
| } |
| |
| void |
| IRBuilder::genThrowSystemException(CompilationInterface::SystemExceptionId id) { |
| appendInst(instFactory->makeThrowSystemException(id)); |
| } |
| |
| void |
| IRBuilder::genThrowLinkingException(Class_Handle encClass, U_32 CPIndex, U_32 operation) { |
| appendInst(instFactory->makeThrowLinkingException(encClass, CPIndex, operation)); |
| } |
| |
| Opnd* |
| IRBuilder::genCatch(Type* exceptionType) { |
| Opnd* dst = createOpnd(exceptionType); |
| appendInst(instFactory->makeCatch(dst)); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genSaveRet() { |
| Opnd *dst = createOpnd(typeManager->getIntPtrType()); |
| appendInst(instFactory->makeSaveRet(dst)); |
| return dst; |
| } |
| |
| |
| |
| void |
| IRBuilder::genPrefetch(Opnd *addr) { |
| appendInst(instFactory->makePrefetch(propagateCopy(addr))); |
| } |
| |
| Opnd* IRBuilder::createTypeOpnd(ObjectType* type) { |
| Opnd* res = NULL; |
| POINTER_SIZE_SINT val = (POINTER_SIZE_SINT)type->getRuntimeIdentifier(); |
| res = genLdConstant(val); |
| return res; |
| } |
| // Calls |
| |
| Opnd* IRBuilder::genIndirectCallWithResolve(Type* returnType, |
| Opnd* tauNullCheckedFirstArg, |
| Opnd* tauTypesChecked, |
| U_32 numArgs, |
| Opnd* args[], |
| ObjectType* ch, |
| JavaByteCodes bc, |
| U_32 cpIndex, |
| MethodSignature* sig |
| ) |
| { |
| assert(!returnType->isNullObject()); |
| Opnd* callAddrOpnd = lookupHash(Op_VMHelperCall, bc, cpIndex, numArgs>0?args[0]->getId() : 0); |
| if (tauTypesChecked == NULL) { |
| tauTypesChecked = genTauUnsafe(); |
| } |
| |
| if (callAddrOpnd == NULL) { |
| VM_RT_SUPPORT vmHelperId = VM_RT_UNKNOWN; |
| MemoryManager& mm = irManager->getMemoryManager(); |
| Opnd* clsOpnd = createTypeOpnd(ch); |
| Opnd* idxOpnd = genLdConstant((int)cpIndex); |
| U_32 numHelperArgs = 0; |
| Opnd** helperArgs = new(mm)Opnd*[3]; |
| helperArgs[0] = clsOpnd; |
| helperArgs[1] = idxOpnd; |
| helperArgs[2] = NULL; |
| switch(bc) { |
| case OPCODE_INVOKESTATIC: |
| vmHelperId = VM_RT_GET_INVOKESTATIC_ADDR_WITHRESOLVE; |
| numHelperArgs = 2; |
| break; |
| case OPCODE_INVOKEVIRTUAL: |
| vmHelperId = VM_RT_GET_INVOKEVIRTUAL_ADDR_WITHRESOLVE; |
| helperArgs[2] = args[0]; |
| numHelperArgs = 3; |
| break; |
| case OPCODE_INVOKESPECIAL: |
| vmHelperId = VM_RT_GET_INVOKE_SPECIAL_ADDR_WITHRESOLVE; |
| numHelperArgs = 2; |
| break; |
| case OPCODE_INVOKEINTERFACE: |
| vmHelperId = VM_RT_GET_INVOKEINTERFACE_ADDR_WITHRESOLVE; |
| helperArgs[2] = args[0]; |
| numHelperArgs = 3; |
| break; |
| default: assert(0); |
| } |
| callAddrOpnd = genVMHelperCall(vmHelperId, typeManager->getUnresolvedMethodPtrType(ch, cpIndex, sig), numHelperArgs, helperArgs); |
| insertHash(Op_VMHelperCall, bc, cpIndex, numArgs>0?args[0]->getId() : 0, callAddrOpnd->getInst()); |
| } |
| |
| return genIndirectMemoryCall(returnType, callAddrOpnd, tauNullCheckedFirstArg, tauTypesChecked, numArgs, args); |
| } |
| |
| |
| Opnd* |
| IRBuilder::genDirectCall(MethodDesc* methodDesc, |
| Type* returnType, |
| Opnd* tauNullCheckedFirstArg, |
| Opnd* tauTypesChecked, |
| U_32 numArgs, |
| Opnd* args[]) |
| { |
| if (!tauNullCheckedFirstArg) |
| tauNullCheckedFirstArg = genTauUnsafe(); |
| else |
| tauNullCheckedFirstArg = propagateCopy(tauNullCheckedFirstArg); |
| if (!tauTypesChecked) |
| tauTypesChecked = genTauUnsafe(); |
| else |
| tauTypesChecked = propagateCopy(tauTypesChecked); |
| |
| if (irBuilderFlags.expandCallAddrs) { |
| return genIndirectMemoryCall(returnType, genLdFunAddrSlot(methodDesc), |
| tauNullCheckedFirstArg, tauTypesChecked, |
| numArgs, args); |
| } |
| for (U_32 i=0; i<numArgs; i++) { |
| args[i] = propagateCopy(args[i]); |
| } |
| Opnd* dst = createOpnd(returnType); |
| appendInst(instFactory->makeDirectCall(dst, tauNullCheckedFirstArg, tauTypesChecked, |
| numArgs, args, methodDesc)); |
| |
| // Note that type initialization should be made available for this type |
| // and all its ancestor types. |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genTauVirtualCall(MethodDesc* methodDesc, |
| Type* returnType, |
| Opnd* tauNullCheckedFirstArg, |
| Opnd* tauTypesChecked, |
| U_32 numArgs, |
| Opnd* args[]) |
| { |
| if(!methodDesc->isVirtual()) |
| // Must de-virtualize - no vtable |
| return genDirectCall(methodDesc, returnType, |
| tauNullCheckedFirstArg, tauTypesChecked, |
| numArgs, args); |
| for (U_32 i=0; i<numArgs; i++) { |
| args[i] = propagateCopy(args[i]); |
| } |
| // callvirt can throw a null pointer exception |
| if (!tauNullCheckedFirstArg || |
| (tauNullCheckedFirstArg->getInst()->getOpcode() == Op_TauUnsafe)) { |
| // if no null check yet, do one |
| tauNullCheckedFirstArg = genTauCheckNull(args[0]); |
| } else { |
| tauNullCheckedFirstArg = propagateCopy(tauNullCheckedFirstArg); |
| } |
| if (!tauTypesChecked || (tauTypesChecked->getInst()->getOpcode() == Op_TauUnsafe)) { |
| // if no type check available yet |
| tauTypesChecked = genTauHasTypeWithConv(&args[0], methodDesc->getParentType()); |
| } else { |
| tauTypesChecked = propagateCopy(tauTypesChecked); |
| } |
| if (irBuilderFlags.doSimplify) { |
| Opnd *dst = simplifier->simplifyTauVirtualCall(methodDesc, |
| returnType, |
| tauNullCheckedFirstArg, |
| tauTypesChecked, |
| numArgs, |
| args); |
| if (dst) return dst; |
| } |
| |
| if (irBuilderFlags.expandVirtualCallAddrs) { |
| return genIndirectMemoryCall(returnType, |
| genTauLdVirtFunAddrSlot(args[0], |
| tauNullCheckedFirstArg, |
| methodDesc), |
| tauNullCheckedFirstArg, |
| tauTypesChecked, |
| numArgs, args); |
| } |
| Opnd *dst = createOpnd(returnType); |
| appendInst(instFactory->makeTauVirtualCall(dst, tauNullCheckedFirstArg, |
| tauTypesChecked, numArgs, args, methodDesc)); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genJitHelperCall(JitHelperCallId helperId, |
| Type* returnType, |
| U_32 numArgs, |
| Opnd* args[]) { |
| for (U_32 i=0; i<numArgs; i++) { |
| args[i] = propagateCopy(args[i]); |
| } |
| Opnd * dst = createOpnd(returnType); |
| appendInst(instFactory->makeJitHelperCall(dst, helperId, NULL, NULL, numArgs, args)); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genJitHelperCall(JitHelperCallId helperId, |
| Type* returnType, |
| Opnd* tauNullCheckedRefArgs, |
| Opnd* tauTypesChecked, |
| U_32 numArgs, |
| Opnd* args[]) { |
| for (U_32 i=0; i<numArgs; i++) { |
| args[i] = propagateCopy(args[i]); |
| } |
| Opnd * dst = createOpnd(returnType); |
| appendInst(instFactory->makeJitHelperCall(dst, helperId, tauNullCheckedRefArgs, tauTypesChecked, numArgs, args)); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genVMHelperCall(VM_RT_SUPPORT helperId, |
| Type* returnType, |
| U_32 numArgs, |
| Opnd* args[]) { |
| for (U_32 i=0; i<numArgs; i++) { |
| args[i] = propagateCopy(args[i]); |
| } |
| Opnd * dst = createOpnd(returnType); |
| appendInst(instFactory->makeVMHelperCall(dst, helperId, numArgs, args)); |
| return dst; |
| } |
| |
| |
| void |
| IRBuilder::genTauTypeCompare(Opnd *arg0, MethodDesc *methodDesc, LabelInst *target, |
| Opnd *tauNullChecked) { |
| arg0 = propagateCopy(arg0); // null check now is in genLdVTable() |
| Type* type = methodDesc->getParentType(); |
| assert(type->isObject()); |
| // Note that we use the methodDesc's type to obtain the vtable which contains the pointer |
| // to the method. This may be an interface vtable. genLdVTable figures out which. |
| Opnd* vtableThis = genLdVTable(arg0, type); |
| Opnd* vtableClass = createOpnd(typeManager->getVTablePtrType(type)); |
| appendInst(instFactory->makeGetVTableAddr(vtableClass, (ObjectType*)type)); |
| |
| genBranch(Type::VTablePtr, Cmp_EQ, target, vtableThis, vtableClass); |
| } |
| |
| Opnd* |
| IRBuilder::genIndirectCall(Type* returnType, |
| Opnd* funAddr, |
| Opnd* tauNullCheckedFirstArg, |
| Opnd* tauTypesChecked, |
| U_32 numArgs, |
| Opnd* args[]) |
| { |
| for (U_32 i=0; i<numArgs; i++) { |
| args[i] = propagateCopy(args[i]); |
| } |
| Opnd* dst = createOpnd(returnType); |
| |
| if (!tauNullCheckedFirstArg) |
| tauNullCheckedFirstArg = genTauUnsafe(); |
| else |
| tauNullCheckedFirstArg = propagateCopy(tauNullCheckedFirstArg); |
| if (!tauTypesChecked) |
| tauTypesChecked = genTauUnsafe(); |
| else |
| tauTypesChecked = propagateCopy(tauTypesChecked); |
| |
| appendInst(instFactory->makeIndirectCall(dst, funAddr, tauNullCheckedFirstArg, tauTypesChecked, |
| numArgs, args)); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genIndirectMemoryCall(Type* returnType, |
| Opnd* funAddr, |
| Opnd* tauNullCheckedFirstArg, |
| Opnd* tauTypesChecked, |
| U_32 numArgs, |
| Opnd* args[]) |
| { |
| for (U_32 i=0; i<numArgs; i++) { |
| args[i] = propagateCopy(args[i]); |
| } |
| |
| if (!tauNullCheckedFirstArg) |
| tauNullCheckedFirstArg = genTauUnsafe(); |
| else |
| tauNullCheckedFirstArg = propagateCopy(tauNullCheckedFirstArg); |
| if (!tauTypesChecked) |
| tauTypesChecked = genTauUnsafe(); |
| else |
| tauTypesChecked = propagateCopy(tauTypesChecked); |
| |
| Opnd* dst = createOpnd(returnType); |
| appendInst(instFactory->makeIndirectMemoryCall(dst, funAddr, tauNullCheckedFirstArg, |
| tauTypesChecked, numArgs, args)); |
| return dst; |
| } |
| |
| void |
| IRBuilder::genReturn(Opnd* src, Type* retType) { |
| src = propagateCopy(src); |
| if(Log::isEnabled()) { |
| Type* srcType = src->getType(); |
| bool convOk = retType == srcType; |
| convOk = convOk || (retType->isObject() && (srcType->isObject() || srcType->isUnmanagedPtr())); |
| if (!convOk){ |
| assert(!typeManager->isLazyResolutionMode()); |
| Log::out() << "ERROR !!!! IRBuilder: unimplemented: ret typecheck !!!\n"; |
| } |
| } |
| appendInst(instFactory->makeReturn(src)); |
| } |
| |
| void |
| IRBuilder::genReturn() { |
| appendInst(instFactory->makeReturn()); |
| } |
| |
| void |
| IRBuilder::genRet(Opnd* src) { |
| appendInst(instFactory->makeRet(src)); |
| } |
| |
| // Move instruction |
| Opnd* |
| IRBuilder::genCopy(Opnd* src) { |
| src = propagateCopy(src); |
| Opnd* dst = createOpnd(src->getType()); |
| appendInst(instFactory->makeCopy(dst, src)); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genArgCoercion(Type* argType, Opnd* actualArg) { |
| actualArg = propagateCopy(actualArg); |
| if (actualArg->getType() == argType) |
| return actualArg; |
| return actualArg; |
| } |
| |
| // actual parameter and variable definitions |
| Opnd* |
| IRBuilder::genArgDef(Modifier mod, Type* type) { |
| Opnd* dst = opndManager->createArgOpnd(type); |
| appendInst(instFactory->makeDefArg(mod, dst)); |
| DefArgModifier defMod = mod.getDefArgModifier(); |
| switch (defMod) { |
| case NonNullThisArg: |
| genTauIsNonNull(dst); |
| break; |
| case SpecializedToExactType: |
| genTauHasExactType(dst, type); |
| break; |
| case DefArgBothModifiers: |
| genTauIsNonNull(dst); |
| genTauHasExactType(dst, type); |
| break; |
| case DefArgNoModifier: |
| break; |
| default: |
| assert(0); |
| } |
| genTauHasType(dst, type); |
| return dst; |
| } |
| |
| VarOpnd* |
| IRBuilder::genVarDef(Type* type, bool isPinned) { |
| return opndManager->createVarOpnd(type, isPinned); |
| } |
| |
| // Phi-node instruction |
| Opnd* |
| IRBuilder::genPhi(U_32 numArgs, Opnd* args[]) { |
| for (U_32 i=0; i<numArgs; i++) { |
| args[i] = propagateCopy(args[i]); |
| } |
| Opnd* dst = createOpnd(args[0]->getType()); |
| appendInst(instFactory->makePhi(dst, numArgs, args)); |
| return dst; |
| } |
| |
| // Pi-node instruction (splits live range for bounds analysis) |
| Opnd* |
| IRBuilder::genTauPi(Opnd *src, Opnd *tau, PiCondition *cond) { |
| src = propagateCopy(src); |
| tau = propagateCopy(tau); |
| PiOpnd* dst = createPiOpnd(src); |
| appendInst(instFactory->makeTauPi(dst, src, tau, cond)); |
| return dst; |
| } |
| |
| // load instructions |
| Opnd* |
| IRBuilder::genLdConstant(I_32 val) { |
| Operation operation(Op_LdConstant, Type::Int32, Modifier()); |
| U_32 hashcode = operation.encodeForHashing(); |
| Opnd* dst = lookupHash(hashcode, (U_32) val); |
| if (dst) return dst; |
| dst = createOpnd(typeManager->getInt32Type()); |
| appendInst(instFactory->makeLdConst(dst, val)); |
| insertHash(hashcode, (U_32) val, dst->getInst()); |
| return dst; |
| } |
| Opnd* |
| IRBuilder::genLdConstant(int64 val) { |
| Operation operation(Op_LdConstant, Type::Int64, Modifier()); |
| U_32 hashcode = operation.encodeForHashing(); |
| Opnd* dst = lookupHash(hashcode, (U_32) (val >> 32), (U_32) (val & 0xffffffff)); |
| if (dst) return dst; |
| dst = createOpnd(typeManager->getInt64Type()); |
| appendInst(instFactory->makeLdConst(dst, val)); |
| insertHash(hashcode, (U_32) (val >> 32), (U_32) (val & 0xffffffff), dst->getInst()); |
| return dst; |
| } |
| Opnd* IRBuilder::genLdConstant(float val) { |
| ConstInst::ConstValue cv; |
| cv.s = val; |
| U_32 word1 = cv.dword1; |
| U_32 word2 = cv.dword2; |
| Operation operation(Op_LdConstant, Type::Single, Modifier()); |
| U_32 hashcode = operation.encodeForHashing(); |
| Opnd* dst = lookupHash(hashcode, word1, word2); |
| if (dst) return dst; |
| dst = createOpnd(typeManager->getSingleType()); |
| appendInst(instFactory->makeLdConst(dst, val)); |
| insertHash(hashcode, word1, word2, dst->getInst()); |
| return dst; |
| } |
| Opnd* |
| IRBuilder::genLdConstant(double val) { |
| ConstInst::ConstValue cv; |
| cv.d = val; |
| U_32 word1 = cv.dword1; |
| U_32 word2 = cv.dword2; |
| Operation operation(Op_LdConstant, Type::Double, Modifier()); |
| U_32 hashcode = operation.encodeForHashing(); |
| Opnd* dst = lookupHash(hashcode, word1, word2); |
| if (dst) return dst; |
| dst = createOpnd(typeManager->getDoubleType()); |
| appendInst(instFactory->makeLdConst(dst, val)); |
| insertHash(hashcode, word1, word2, dst->getInst()); |
| return dst; |
| } |
| Opnd* |
| IRBuilder::genLdConstant(Type *ptrtype, ConstInst::ConstValue val) { |
| U_32 word1 = val.dword1; |
| U_32 word2 = val.dword2; |
| Operation operation(Op_LdConstant, ptrtype->tag, Modifier()); |
| U_32 hashcode = operation.encodeForHashing(); |
| Opnd* dst = lookupHash(hashcode, word1, word2); |
| if (dst) return dst; |
| dst = createOpnd(ptrtype); |
| appendInst(instFactory->makeLdConst(dst, val)); |
| insertHash(hashcode, word1, word2, dst->getInst()); |
| return dst; |
| } |
| Opnd* |
| IRBuilder::genLdFloatConstant(double val) { |
| ConstInst::ConstValue cv; |
| cv.d = val; |
| U_32 word1 = cv.dword1; |
| U_32 word2 = cv.dword2; |
| Operation operation(Op_LdConstant, Type::Float, Modifier()); |
| U_32 hashcode = operation.encodeForHashing(); |
| Opnd* dst = lookupHash(hashcode, word1, word2); |
| if (dst) return dst; |
| dst = createOpnd(typeManager->getFloatType()); |
| appendInst(instFactory->makeLdConst(dst, val)); |
| insertHash(hashcode, word1, word2, dst->getInst()); |
| return dst; |
| } |
| Opnd* |
| IRBuilder::genLdFloatConstant(float val) { |
| ConstInst::ConstValue cv; |
| cv.dword1 = 0; |
| cv.dword2 = 0; |
| cv.s = val; |
| U_32 word1 = cv.dword1; |
| U_32 word2 = cv.dword2; |
| Operation operation(Op_LdConstant, Type::Float, Modifier()); |
| U_32 hashcode = operation.encodeForHashing(); |
| Opnd* dst = lookupHash(hashcode, word1, word2); |
| if (dst) return dst; |
| dst = createOpnd(typeManager->getFloatType()); |
| appendInst(instFactory->makeLdConst(dst, val)); |
| insertHash(hashcode, word1, word2, dst->getInst()); |
| return dst; |
| } |
| Opnd* |
| IRBuilder::genLdNull() { |
| Operation operation(Op_LdConstant, Type::NullObject, Modifier()); |
| U_32 hashcode = operation.encodeForHashing(); |
| Opnd* dst = lookupHash(hashcode); |
| if (dst) return dst; |
| dst = createOpnd(typeManager->getNullObjectType()); |
| appendInst(instFactory->makeLdNull(dst)); |
| insertHash(hashcode, dst->getInst()); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genLdRef(MethodDesc* enclosingMethod, U_32 stringToken, Type* type) { |
| bool uncompress = irBuilderFlags.compressedReferences; |
| |
| Modifier mod = uncompress ? AutoCompress_Yes : AutoCompress_No; |
| Opnd* dst = createOpnd(type); |
| |
| appendInst(instFactory->makeLdRef(mod, dst, enclosingMethod, stringToken)); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genLdVar(Type* dstType, VarOpnd* var) { |
| if (!var->isAddrTaken()) { |
| Opnd *dst = lookupHash(Op_LdVar, var); |
| if (dst) return dst; |
| |
| dst = createOpnd(dstType); |
| appendInst(instFactory->makeLdVar(dst, var)); |
| insertHash(Op_LdVar, var, dst->getInst()); |
| return dst; |
| } else { |
| Opnd *dst = createOpnd(dstType); |
| appendInst(instFactory->makeLdVar(dst, var)); |
| return dst; |
| } |
| } |
| |
| Opnd* |
| IRBuilder::genLdVarAddr(VarOpnd* var) { |
| Opnd* dst = lookupHash(Op_LdVarAddr, var); |
| if (dst) return dst; |
| |
| |
| var->setAddrTaken(); |
| dst = createOpnd(typeManager->getManagedPtrType(var->getType())); |
| appendInst(instFactory->makeLdVarAddr(dst, var)); |
| insertHash(Op_LdVarAddr, var, dst->getInst()); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genLdInd(Type* type, Opnd *ptr) |
| { |
| ptr = propagateCopy(ptr); |
| Opnd *tauUnsafe = genTauUnsafe(); |
| bool uncompress = false; |
| if (irBuilderFlags.compressedReferences && type->isObject()) { |
| assert(!type->isCompressedReference()); |
| uncompress = true; |
| } |
| Modifier mod = uncompress ? AutoCompress_Yes : AutoCompress_No; |
| Opnd *dst = genTauLdInd(mod, type, type->tag, ptr, |
| tauUnsafe, tauUnsafe); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genTauLdInd(Modifier mod, Type* type, Type::Tag ldType, Opnd* ptr, |
| Opnd *tauBaseNonNull, Opnd *tauAddressInRange) { |
| ptr = propagateCopy(ptr); |
| tauBaseNonNull = propagateCopy(tauBaseNonNull); |
| tauAddressInRange = propagateCopy(tauAddressInRange); |
| Opnd* dst = createOpnd(type); |
| appendInst(instFactory->makeTauLdInd(mod, ldType, dst, ptr, |
| tauBaseNonNull, tauAddressInRange)); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genLdRef(Modifier mod, Type* type, |
| U_32 token, MethodDesc *enclosingMethod) |
| { |
| Opnd* dst = createOpnd(type); |
| appendInst(instFactory->makeLdRef(mod, dst, enclosingMethod, token)); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genLdField(Type* type, Opnd* base, FieldDesc* fieldDesc) { |
| assert(!fieldDesc->isStatic()); |
| base = propagateCopy(base); |
| Opnd *tauNullCheck = genTauCheckNull(base); |
| Opnd *tauAddressInRange = |
| genTauHasType(base, fieldDesc->getParentType()); |
| |
| bool uncompress = false; |
| if (irBuilderFlags.compressedReferences && type->isObject()) { |
| assert(!type->isCompressedReference()); |
| uncompress = true; |
| } |
| Modifier mod = uncompress ? AutoCompress_Yes : AutoCompress_No; |
| if (irBuilderFlags.expandMemAddrs) { |
| return genTauLdInd(mod, type, type->tag, |
| genLdFieldAddr(type, base, fieldDesc), |
| tauNullCheck, tauAddressInRange); |
| } |
| |
| Opnd* dst = createOpnd(type); |
| appendInst(instFactory->makeTauLdField(mod, type, dst, base, |
| tauNullCheck, tauAddressInRange, |
| fieldDesc)); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genLdFieldWithResolve(Type* type, Opnd* base, ObjectType* enclClass, U_32 cpIndex) { |
| base = propagateCopy(base); |
| Opnd *tauNullCheck = genTauCheckNull(base); |
| Opnd *tauAddressInRange = genTauSafe(); |
| |
| bool uncompress = false; |
| if (irBuilderFlags.compressedReferences && type->isObject()) { |
| assert(!type->isCompressedReference()); |
| uncompress = true; |
| } |
| Modifier mod = uncompress ? AutoCompress_Yes : AutoCompress_No; |
| assert(irBuilderFlags.expandMemAddrs); |
| |
| Opnd* addr = genLdFieldAddrWithResolve(type, base, enclClass, cpIndex, false); |
| return genTauLdInd(mod, type, type->tag, addr, tauNullCheck, tauAddressInRange); |
| } |
| |
| void |
| IRBuilder::genInitType(NamedType* type) { |
| if (!type->needsInitialization()) { |
| return; |
| } |
| MethodDesc * m = irManager->getCompilationInterface().getMethodToCompile(); |
| NamedType* classType = m->getParentType(); |
| if (type == classType) { |
| return; |
| } |
| Opnd* opnd = lookupHash(Op_InitType, type->getId()); |
| if (opnd) return; // no need to re-initialize |
| |
| insertHash(Op_InitType, type->getId(), appendInst(instFactory->makeInitType(type))); |
| } |
| |
| Opnd* |
| IRBuilder::genLdStaticWithResolve(Type* type, ObjectType* enclClass, U_32 cpIdx) { |
| bool uncompress = false; |
| if (irBuilderFlags.compressedReferences && type->isObject()) { |
| assert(!type->isCompressedReference()); |
| uncompress = true; |
| } |
| Modifier mod = uncompress ? AutoCompress_Yes : AutoCompress_No; |
| |
| Opnd *tauOk = genTauSafe(); // static field, always safe |
| Opnd* addrOpnd = genLdStaticAddrWithResolve(type, enclClass, cpIdx, false); |
| return genTauLdInd(mod, type, type->tag, addrOpnd, tauOk, tauOk); |
| } |
| |
| Opnd* |
| IRBuilder::genLdStatic(Type* type, FieldDesc* fieldDesc) { |
| bool uncompress = false; |
| if (irBuilderFlags.compressedReferences && type->isObject()) { |
| assert(!type->isCompressedReference()); |
| uncompress = true; |
| } |
| Modifier mod = uncompress ? AutoCompress_Yes : AutoCompress_No; |
| |
| genInitType(fieldDesc->getParentType()); |
| if (irBuilderFlags.expandMemAddrs) { |
| Opnd *tauOk = genTauSafe(); // static field, always safe |
| return genTauLdInd(mod, type, type->tag, genLdStaticAddr(type, fieldDesc), |
| tauOk, tauOk); |
| } |
| |
| Opnd* dst = createOpnd(type); |
| appendInst(instFactory->makeLdStatic(mod, type, dst, fieldDesc)); |
| return dst; |
| } |
| |
| |
| Opnd* |
| IRBuilder::genLdElem(Type* type, Opnd* array, Opnd* index, Opnd* tauNullChecked, Opnd* tauAddressInRange) { |
| |
| assert(tauNullChecked); |
| assert(tauAddressInRange); |
| |
| array = propagateCopy(array); |
| index = propagateCopy(index); |
| |
| bool uncompress = false; |
| if (irBuilderFlags.compressedReferences && type->isObject()) { |
| assert(!type->isCompressedReference()); |
| uncompress = true; |
| } |
| Modifier mod = uncompress ? AutoCompress_Yes : AutoCompress_No; |
| |
| if (irBuilderFlags.expandMemAddrs) { |
| return genTauLdInd(mod, type, type->tag, |
| genLdElemAddrNoChecks(type, array, index), |
| tauNullChecked, tauAddressInRange); |
| } |
| Opnd* dst = createOpnd(type); |
| appendInst(instFactory->makeTauLdElem(mod, type, dst, array, index, |
| tauNullChecked, tauAddressInRange)); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genLdElem(Type* type, Opnd* array, Opnd* index) { |
| |
| array = propagateCopy(array); |
| index = propagateCopy(index); |
| |
| Opnd *tauNullChecked = genTauCheckNull(array); |
| Opnd *tauBoundsChecked = genTauCheckBounds(array, index, tauNullChecked); |
| Opnd *tauBaseTypeChecked = genTauHasType(array, array->getType()); |
| Opnd *tauAddressInRange = genTauAnd(tauBoundsChecked, tauBaseTypeChecked); |
| |
| return genLdElem(type,array,index,tauNullChecked,tauAddressInRange); |
| } |
| |
| Opnd* |
| IRBuilder::genLdFieldAddr(Type* type, Opnd* base, FieldDesc* fieldDesc) { |
| assert(!fieldDesc->isStatic()); |
| |
| base = propagateCopy(base); |
| |
| genTauCheckNull(base); |
| |
| Opnd* dst = lookupHash(Op_LdFieldAddr, base->getId(), fieldDesc->getId()); |
| if (dst) return dst; |
| |
| if (base->getType()->isIntPtr()) { |
| // unmanaged pointer |
| dst = createOpnd(typeManager->getIntPtrType()); |
| } else if (irBuilderFlags.compressedReferences && type->isObject()) { |
| // until VM type system is upgraded, |
| // fieldDesc type will have uncompressed ref type; |
| // compress it |
| assert(!type->isCompressedReference()); |
| Type *compressedType = typeManager->compressType(type); |
| dst = createOpnd(typeManager->getManagedPtrType(compressedType)); |
| } else { |
| dst = createOpnd(typeManager->getManagedPtrType(type)); |
| } |
| appendInst(instFactory->makeLdFieldAddr(dst, base, fieldDesc)); |
| insertHash(Op_LdFieldAddr, base->getId(), fieldDesc->getId(), dst->getInst()); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genLdFieldAddrWithResolve(Type* type, Opnd* base, ObjectType* enclClass, U_32 cpIndex, bool putfield) { |
| base = propagateCopy(base); |
| genTauCheckNull(base); |
| |
| //1. loading field offset |
| JavaByteCodes opcode = putfield? OPCODE_PUTFIELD : OPCODE_GETFIELD; |
| Opnd* dst = lookupHash(Op_VMHelperCall, opcode, base->getId(), cpIndex); |
| if (dst) return dst; |
| |
| if (irBuilderFlags.compressedReferences && type->isObject()) { |
| // until VM type system is upgraded, |
| // fieldDesc type will have uncompressed ref type; |
| // compress it |
| assert(!type->isCompressedReference()); |
| Type *compressedType = typeManager->compressType(type); |
| dst = createOpnd(typeManager->getManagedPtrType(compressedType)); |
| } else { |
| dst = createOpnd(typeManager->getManagedPtrType(type)); |
| } |
| Opnd** args = new (irManager->getMemoryManager()) Opnd*[3]; |
| args[0] = createTypeOpnd(enclClass); |
| args[1] = genLdConstant((int)cpIndex); |
| args[2] = genLdConstant((int)putfield?1:0); |
| Opnd* offsetOpnd = genVMHelperCall(VM_RT_GET_NONSTATIC_FIELD_OFFSET_WITHRESOLVE, |
| typeManager->getIntPtrType(), 3, args); |
| insertHash(Op_VMHelperCall, opcode, base->getId(), cpIndex, dst->getInst()); |
| |
| //2. adding the offset to object opnd -> getting the address of the field |
| appendInst(instFactory->makeAddOffset(dst, base, offsetOpnd)); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genLdStaticAddr(Type* type, FieldDesc* fieldDesc) { |
| genInitType(fieldDesc->getParentType()); |
| |
| Opnd* dst = lookupHash(Op_LdStaticAddr, fieldDesc->getId()); |
| if (dst) return dst; |
| |
| if (irBuilderFlags.compressedReferences && type->isObject()) { |
| // until VM type system is upgraded, |
| // fieldDesc type will have uncompressed ref type; |
| // compress it |
| assert(!type->isCompressedReference()); |
| Type *compressedType = typeManager->compressType(type); |
| dst = createOpnd(typeManager->getManagedPtrType(compressedType)); |
| } else { |
| dst = createOpnd(typeManager->getManagedPtrType(type)); |
| } |
| appendInst(instFactory->makeLdStaticAddr(dst, fieldDesc)); |
| insertHash(Op_LdStaticAddr, fieldDesc->getId(), dst->getInst()); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genLdStaticAddrWithResolve(Type* type, ObjectType* enclClass, U_32 cpIndex, bool putfield) { |
| JavaByteCodes opcode = putfield ? OPCODE_PUTSTATIC : OPCODE_GETSTATIC; |
| Opnd* dst = lookupHash(Op_VMHelperCall, opcode, cpIndex); |
| if (dst) return dst; |
| |
| if (irBuilderFlags.compressedReferences && type->isObject()) { |
| // until VM type system is upgraded, |
| // fieldDesc type will have uncompressed ref type; |
| // compress it |
| assert(!type->isCompressedReference()); |
| Type *compressedType = typeManager->compressType(type); |
| dst = createOpnd(typeManager->getManagedPtrType(compressedType)); |
| } else { |
| dst = createOpnd(typeManager->getManagedPtrType(type)); |
| } |
| Opnd** args = new (irManager->getMemoryManager()) Opnd*[3]; |
| args[0] = createTypeOpnd(enclClass); |
| args[1] = genLdConstant((int)cpIndex); |
| args[2] = genLdConstant((int)putfield?1:0); |
| appendInst(instFactory->makeVMHelperCall(dst, VM_RT_GET_STATIC_FIELD_ADDR_WITHRESOLVE, 3, args)); |
| insertHash(Op_VMHelperCall, OPCODE_GETSTATIC, cpIndex, dst->getInst()); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genLdElemAddr(Type* elemType, Opnd* array, Opnd* index) { |
| // null and bounds checks |
| index = propagateCopy(index); |
| array = propagateCopy(array); |
| Opnd *tauNullChecked = genTauCheckNull(array); |
| genTauCheckBounds(array, index, tauNullChecked); |
| return genLdElemAddrNoChecks(elemType, array, index); |
| } |
| |
| Opnd* |
| IRBuilder::genLdElemAddrNoChecks(Type* elemType, Opnd* array, Opnd* index) { |
| Opnd* dst; |
| if (irBuilderFlags.expandElemAddrs) { |
| // |
| // boundscheck array, index |
| // ldarraybase array --> base |
| // addindex base, index --> dst |
| // |
| return genAddScaledIndex(genLdArrayBaseAddr(elemType, array), index); |
| } else { |
| // |
| // Op_LdElemAddr |
| // |
| dst = lookupHash(Op_LdElemAddr, array, index); |
| if (dst) return dst; |
| |
| if (irBuilderFlags.compressedReferences && elemType->isObject()) { |
| // until VM type system is upgraded, |
| // fieldDesc type will have uncompressed ref type; |
| // compress it |
| assert(!elemType->isCompressedReference()); |
| Type *compressedType = typeManager->compressType(elemType); |
| dst = createOpnd(typeManager->getManagedPtrType(compressedType)); |
| } else { |
| dst = createOpnd(typeManager->getManagedPtrType(elemType)); |
| } |
| appendInst(instFactory->makeLdElemAddr(elemType, dst, array, index)); |
| insertHash(Op_LdElemAddr, array, index, dst->getInst()); |
| } |
| |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genLdFunAddr(MethodDesc* methodDesc) { |
| Opnd* dst = lookupHash(Op_LdFunAddr, methodDesc->getId()); |
| if (dst) return dst; |
| |
| dst = createOpnd(typeManager->getMethodPtrType(methodDesc)); |
| appendInst(instFactory->makeLdFunAddr(dst, methodDesc)); |
| insertHash(Op_LdFunAddr, methodDesc->getId(), dst->getInst()); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genLdFunAddrSlot(MethodDesc* methodDesc) { |
| Opnd* dst = lookupHash(Op_LdFunAddrSlot, methodDesc->getId()); |
| if (dst) return dst; |
| |
| |
| dst = createOpnd(typeManager->getMethodPtrType(methodDesc)); |
| appendInst(instFactory->makeLdFunAddrSlot(dst, methodDesc)); |
| insertHash(Op_LdFunAddrSlot, methodDesc->getId(), dst->getInst()); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genLdVTable(Opnd* base, Type* type) { |
| base = propagateCopy(base); |
| Opnd *tauNullChecked = genTauCheckNull(base); |
| |
| return genTauLdVTable(base, tauNullChecked, type); |
| } |
| |
| Opnd* |
| IRBuilder::genTauLdVTable(Opnd* base, Opnd *tauNullChecked, Type* type) { |
| base = propagateCopy(base); |
| |
| SsaOpnd* obj = base->asSsaOpnd(); |
| assert(obj); |
| Opnd* dst = NULL; |
| if (type->isInterface()) { |
| dst = lookupHash(Op_TauLdIntfcVTableAddr, base->getId(), type->getId()); |
| if (dst) return dst; |
| |
| if (irBuilderFlags.useNewTypeSystem) { |
| NamedType* iType = type->asNamedType(); |
| assert(iType); |
| dst = createOpnd(typeManager->getITablePtrObjType(obj, iType)); |
| } else { |
| dst = createOpnd(typeManager->getVTablePtrType(type)); |
| } |
| appendInst(instFactory->makeTauLdIntfcVTableAddr(dst, base, type)); |
| insertHash(Op_TauLdIntfcVTableAddr, base->getId(), type->getId(), |
| dst->getInst()); |
| } else if (type->isClass()) { |
| dst = lookupHash(Op_TauLdVTableAddr, base); |
| if (dst) return dst; |
| |
| if (irBuilderFlags.useNewTypeSystem) { |
| dst = createOpnd(typeManager->getVTablePtrObjType(obj)); |
| } else { |
| dst = createOpnd(typeManager->getVTablePtrType(base->getType())); |
| } |
| appendInst(instFactory->makeTauLdVTableAddr(dst, base, tauNullChecked)); |
| insertHash(Op_TauLdVTableAddr, base, dst->getInst()); |
| } else { |
| assert(0); // shouldn't happen |
| } |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genGetVTable(ObjectType* type) { |
| assert(type->isClass() && (!type->isAbstract() || type->isArray())); |
| Opnd* dst = lookupHash(Op_GetVTableAddr, type->getId()); |
| if (dst) return dst; |
| |
| dst = createOpnd(typeManager->getVTablePtrType(type)); |
| appendInst(instFactory->makeGetVTableAddr(dst, type)); |
| insertHash(Op_GetVTableAddr, type->getId(), dst->getInst()); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genGetClassObj(ObjectType* type) { |
| assert(type->isClass()); |
| Opnd* dst = lookupHash(Op_GetClassObj, type->getId()); |
| if (dst) return dst; |
| |
| Type* dstType = irManager->getTypeManager().getSystemClassType(); |
| dst = createOpnd(dstType); |
| appendInst(instFactory->makeGetClassObj(dst, type)); |
| insertHash(Op_GetClassObj, type->getId(), dst->getInst()); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genLdVirtFunAddr(Opnd* base, MethodDesc* methodDesc) { |
| base = propagateCopy(base); |
| Opnd* dst = lookupHash(Op_TauLdVirtFunAddr, base->getId(), |
| methodDesc->getId()); |
| if (dst) return dst; |
| |
| Opnd *tauNullChecked = genTauCheckNull(base); |
| Type *methodType = methodDesc->getParentType(); |
| Opnd* vtableOpnd = genTauLdVTable(base, tauNullChecked, methodType); |
| Opnd *tauVtableHasMethod = genTauHasType(base, methodType); |
| |
| dst = createOpnd(typeManager->getMethodPtrType(methodDesc)); |
| appendInst(instFactory->makeTauLdVirtFunAddr(dst, vtableOpnd, |
| tauVtableHasMethod, |
| methodDesc)); |
| insertHash(Op_TauLdVirtFunAddr, vtableOpnd->getId(), methodDesc->getId(), |
| dst->getInst()); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genTauLdVirtFunAddrSlot(Opnd* base, Opnd *tauOk, MethodDesc* methodDesc) { |
| base = propagateCopy(base); |
| Opnd* dst = lookupHash(Op_TauLdVirtFunAddrSlot, base->getId(), |
| methodDesc->getId()); |
| if (dst) return dst; |
| |
| Opnd *tauNullChecked = genTauCheckNull(base); |
| Opnd* vtableOpnd = genTauLdVTable(base, tauNullChecked, methodDesc->getParentType()); |
| Opnd *tauVtableHasMethod = tauOk; |
| |
| if (irBuilderFlags.useNewTypeSystem) { |
| SsaOpnd* obj = base->asSsaOpnd(); |
| assert(obj); |
| dst = createOpnd(typeManager->getMethodPtrObjType(obj, methodDesc)); |
| } else { |
| dst = createOpnd(typeManager->getMethodPtrType(methodDesc)); |
| } |
| appendInst(instFactory->makeTauLdVirtFunAddrSlot(dst, vtableOpnd, |
| tauVtableHasMethod, |
| methodDesc)); |
| insertHash(Op_TauLdVirtFunAddrSlot, vtableOpnd->getId(), |
| methodDesc->getId(), dst->getInst()); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genArrayLen(Type* dstType, Type::Tag type, Opnd* array) { |
| array = propagateCopy(array); |
| |
| Opnd* dst = lookupHash(Op_TauArrayLen, array->getId()); |
| if (dst) return dst; |
| |
| if (irBuilderFlags.doSimplify) { |
| dst = simplifier->simplifyTauArrayLen(dstType, type, array); |
| if (dst) return dst; |
| } |
| |
| Opnd *tauNonNull = genTauCheckNull(array); |
| Opnd *tauIsArray = genTauHasType(array, array->getType()); |
| |
| return genTauArrayLen(dstType, type, array, tauNonNull, tauIsArray); |
| } |
| |
| Opnd* |
| IRBuilder::genTauArrayLen(Type* dstType, Type::Tag type, Opnd* array, |
| Opnd* tauNullChecked, Opnd *tauTypeChecked) { |
| array = propagateCopy(array); |
| |
| Opnd* dst = lookupHash(Op_TauArrayLen, array->getId()); |
| if (dst) return dst; |
| |
| if (irBuilderFlags.doSimplify) { |
| dst = simplifier->simplifyTauArrayLen(dstType, type, array, tauNullChecked, |
| tauTypeChecked); |
| if (dst) return dst; |
| } |
| dst = createOpnd(dstType); |
| appendInst(instFactory->makeTauArrayLen(dst, type, array, tauNullChecked, |
| tauTypeChecked)); |
| insertHash(Op_TauArrayLen, array->getId(), dst->getInst()); |
| |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genLdArrayBaseAddr(Type* elemType, Opnd* array) { |
| array = propagateCopy(array); |
| |
| Opnd* dst = lookupHash(Op_LdArrayBaseAddr, array); |
| if (dst) return dst; |
| |
| if (irBuilderFlags.useNewTypeSystem) { |
| SsaOpnd* arrayVal = array->asSsaOpnd(); |
| assert(arrayVal); |
| Type* baseType = typeManager->getArrayBaseType(arrayVal); |
| dst = createOpnd(baseType); |
| } else { |
| if (irBuilderFlags.compressedReferences && elemType->isObject()) { |
| // until VM type system is upgraded, |
| // fieldDesc type will have uncompressed ref type; |
| // compress it |
| assert(!elemType->isCompressedReference()); |
| Type *compressedType = typeManager->compressType(elemType); |
| dst = createOpnd(typeManager->getManagedPtrType(compressedType)); |
| } else { |
| dst = createOpnd(typeManager->getManagedPtrType(elemType)); |
| } |
| } |
| appendInst(instFactory->makeLdArrayBaseAddr(elemType, dst, array)); |
| insertHash(Op_LdArrayBaseAddr, array, dst->getInst()); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genAddScaledIndex(Opnd* ptr, Opnd* index) { |
| ptr = propagateCopy(ptr); |
| index = propagateCopy(index); |
| Opnd* dst = lookupHash(Op_AddScaledIndex, ptr, index); |
| if (dst) return dst; |
| |
| if (irBuilderFlags.useNewTypeSystem) { |
| PtrType* ptrType = ptr->getType()->asPtrType(); |
| assert(ptrType); |
| SsaOpnd* indexVar = index->asSsaOpnd(); |
| assert(indexVar); |
| Type* dstType = typeManager->getArrayIndexType(ptrType->getArrayName(), indexVar); |
| dst = createOpnd(dstType); |
| } else { |
| dst = createOpnd(ptr->getType()); |
| } |
| |
| appendInst(instFactory->makeAddScaledIndex(dst, ptr, index)); |
| insertHash(Op_AddScaledIndex, ptr, index, dst->getInst()); |
| return dst; |
| } |
| |
| |
| Opnd* |
| IRBuilder::genUncompressRef(Opnd *compref) |
| { |
| compref = propagateCopy(compref); |
| Opnd* dst = lookupHash(Op_UncompressRef, compref); |
| if (dst) return dst; |
| |
| Type *comprefType = compref->getType(); |
| assert(comprefType->isCompressedReference()); |
| |
| dst = createOpnd(typeManager->uncompressType(comprefType)); |
| appendInst(instFactory->makeUncompressRef(dst, compref)); |
| insertHash(Op_UncompressRef, compref, dst->getInst()); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genCompressRef(Opnd *uncompref) |
| { |
| Type *uncomprefType = uncompref->getType(); |
| |
| uncompref = propagateCopy(uncompref); |
| Opnd* dst = lookupHash(Op_CompressRef, uncompref); |
| if (dst) return dst; |
| |
| uncomprefType = uncompref->getType(); |
| assert(uncomprefType->isReference() && !uncomprefType->isCompressedReference()); |
| |
| dst = createOpnd(typeManager->compressType(uncomprefType)); |
| appendInst(instFactory->makeCompressRef(dst, uncompref)); |
| insertHash(Op_CompressRef, uncompref, dst->getInst()); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genLdFieldOffset(FieldDesc* fieldDesc) |
| { |
| assert(!fieldDesc->isStatic()); |
| |
| Opnd *dst = lookupHash(Op_LdFieldOffset, fieldDesc->getId()); |
| if (dst) return dst; |
| |
| |
| dst = createOpnd(typeManager->getOffsetType()); |
| appendInst(instFactory->makeLdFieldOffset(dst, fieldDesc)); |
| insertHash(Op_LdFieldOffset, fieldDesc->getId(), dst->getInst()); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genLdFieldOffsetPlusHeapbase(FieldDesc* fieldDesc) |
| { |
| assert(!fieldDesc->isStatic()); |
| |
| Opnd *dst = lookupHash(Op_LdFieldOffsetPlusHeapbase, fieldDesc->getId()); |
| if (dst) return dst; |
| |
| |
| dst = createOpnd(typeManager->getOffsetPlusHeapbaseType()); |
| appendInst(instFactory->makeLdFieldOffsetPlusHeapbase(dst, fieldDesc)); |
| insertHash(Op_LdFieldOffsetPlusHeapbase, fieldDesc->getId(), dst->getInst()); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genLdArrayBaseOffset(Type *elemType) |
| { |
| Opnd* dst = lookupHash(Op_LdArrayBaseOffset, elemType->getId()); |
| if (dst) return dst; |
| |
| dst = createOpnd(typeManager->getOffsetType()); |
| appendInst(instFactory->makeLdArrayBaseOffset(dst, elemType)); |
| insertHash(Op_LdArrayBaseOffset, elemType->getId(), dst->getInst()); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genLdArrayBaseOffsetPlusHeapbase(Type *elemType) |
| { |
| Opnd* dst = lookupHash(Op_LdArrayBaseOffsetPlusHeapbase, elemType->getId()); |
| if (dst) return dst; |
| |
| dst = createOpnd(typeManager->getOffsetPlusHeapbaseType()); |
| appendInst(instFactory->makeLdArrayBaseOffsetPlusHeapbase(dst, elemType)); |
| insertHash(Op_LdArrayBaseOffsetPlusHeapbase, elemType->getId(), dst->getInst()); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genLdArrayLenOffset(Type *elemType) |
| { |
| Opnd* dst = lookupHash(Op_LdArrayLenOffset, elemType->getId()); |
| if (dst) return dst; |
| |
| dst = createOpnd(typeManager->getOffsetType()); |
| appendInst(instFactory->makeLdArrayLenOffset(dst, elemType)); |
| insertHash(Op_LdArrayLenOffset, elemType->getId(), dst->getInst()); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genLdArrayLenOffsetPlusHeapbase(Type *elemType) |
| { |
| Opnd* dst = lookupHash(Op_LdArrayLenOffsetPlusHeapbase, elemType->getId()); |
| if (dst) return dst; |
| |
| dst = createOpnd(typeManager->getOffsetPlusHeapbaseType()); |
| appendInst(instFactory->makeLdArrayLenOffsetPlusHeapbase(dst, elemType)); |
| insertHash(Op_LdArrayLenOffsetPlusHeapbase, elemType->getId(), dst->getInst()); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genAddOffset(Type *ptrType, Opnd* ref, Opnd* offset) |
| { |
| ref = propagateCopy(ref); |
| offset = propagateCopy(offset); |
| Opnd* dst = lookupHash(Op_AddOffset, ref, offset); |
| if (dst) return dst; |
| |
| |
| assert(!ref->getType()->isCompressedReference()); |
| assert(offset->getType()->isOffset()); |
| |
| dst = createOpnd(ptrType); |
| appendInst(instFactory->makeAddOffset(dst, ref, offset)); |
| insertHash(Op_AddOffset, ref, offset, dst->getInst()); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genAddOffsetPlusHeapbase(Type *ptrType, Opnd* compref, Opnd* offset) |
| { |
| compref = propagateCopy(compref); |
| offset = propagateCopy(offset); |
| Opnd* dst = lookupHash(Op_AddOffsetPlusHeapbase, compref, offset); |
| if (dst) return dst; |
| |
| |
| assert(compref->getType()->isCompressedReference()); |
| assert(offset->getType()->isOffsetPlusHeapbase()); |
| |
| dst = createOpnd(ptrType); |
| appendInst(instFactory->makeAddOffsetPlusHeapbase(dst, compref, offset)); |
| insertHash(Op_AddOffsetPlusHeapbase, compref, offset, dst->getInst()); |
| return dst; |
| } |
| |
| // store instructions |
| void |
| IRBuilder::genStVar(VarOpnd* var, Opnd* src) { |
| src = propagateCopy(src); |
| appendInst(instFactory->makeStVar(var, src)); |
| if (irBuilderFlags.doCSE) { |
| insertHash(Op_LdVar, var->getId(), src->getInst()); |
| } |
| } |
| |
| void |
| IRBuilder::genStInd(Type* type, |
| Opnd* ptr, |
| Opnd* src) { |
| ptr = propagateCopy(ptr); |
| src = propagateCopy(src); |
| |
| Type *ptrType = ptr->getType(); |
| assert(ptrType->isPtr() || ptrType->isIntPtr()); |
| Type *fieldType = ((PtrType *)ptrType)->getPointedToType(); |
| bool compress = (fieldType->isCompressedReference() && |
| !type->isCompressedReference()); |
| Modifier compressMod = Modifier(compress ? AutoCompress_Yes |
| : AutoCompress_No); |
| |
| Opnd *tauUnsafe = genTauUnsafe(); |
| |
| if (irBuilderFlags.insertWriteBarriers) { |
| appendInst(instFactory->makeTauStInd((Modifier(Store_WriteBarrier)| |
| compressMod), |
| type->tag, src, ptr, |
| tauUnsafe, tauUnsafe, tauUnsafe)); |
| } else { |
| appendInst(instFactory->makeTauStInd((Modifier(Store_NoWriteBarrier)| |
| compressMod), |
| type->tag, src, ptr, |
| tauUnsafe, tauUnsafe, tauUnsafe)); |
| } |
| } |
| |
| void |
| IRBuilder::genTauStInd(Type* type, |
| Opnd* ptr, |
| Opnd* src, |
| Opnd* tauBaseNonNull, |
| Opnd *tauAddressInRange, |
| Opnd* tauElemTypeChecked) { |
| ptr = propagateCopy(ptr); |
| src = propagateCopy(src); |
| |
| Type *ptrType = ptr->getType(); |
| assert(ptrType->isPtr() || ptrType->isIntPtr()); |
| Type *fieldType = ((PtrType *)ptrType)->getPointedToType(); |
| if (fieldType->isArrayElement()) { |
| fieldType = fieldType->getNonValueSupertype(); |
| } |
| bool compress = (fieldType->isCompressedReference() && |
| !type->isCompressedReference()); |
| Modifier compressMod = Modifier(compress ? AutoCompress_Yes |
| : AutoCompress_No); |
| |
| if (irBuilderFlags.insertWriteBarriers) { |
| appendInst(instFactory->makeTauStInd((Modifier(Store_WriteBarrier)| |
| compressMod), |
| type->tag, src, ptr, |
| tauBaseNonNull, tauAddressInRange, tauElemTypeChecked)); |
| } else { |
| appendInst(instFactory->makeTauStInd((Modifier(Store_NoWriteBarrier)| |
| compressMod), |
| type->tag, src, ptr, |
| tauBaseNonNull, tauAddressInRange, tauElemTypeChecked)); |
| } |
| } |
| |
| void |
| IRBuilder::genTauStRef(Type* type, Opnd *objectbase, Opnd* ptr, Opnd* src, |
| Opnd *tauBaseNonNull, Opnd *tauAddressInRange, |
| Opnd *tauElemTypeChecked) { |
| objectbase = propagateCopy(objectbase); |
| ptr = propagateCopy(ptr); |
| src = propagateCopy(src); |
| tauBaseNonNull = propagateCopy(tauBaseNonNull); |
| tauAddressInRange = propagateCopy(tauAddressInRange); |
| tauElemTypeChecked = propagateCopy(tauElemTypeChecked); |
| |
| Type *ptrType = ptr->getType(); |
| assert(ptrType->isPtr()); |
| Type *fieldType = ((PtrType *)ptrType)->getPointedToType(); |
| if (fieldType->isArrayElement()) { |
| fieldType = fieldType->getNonValueSupertype(); |
| } |
| bool compress = (fieldType->isCompressedReference() && |
| !type->isCompressedReference()); |
| Modifier compressMod = Modifier(compress ? AutoCompress_Yes |
| : AutoCompress_No); |
| if (irBuilderFlags.insertWriteBarriers) { |
| appendInst(instFactory->makeTauStRef((Modifier(Store_WriteBarrier)| |
| compressMod), |
| type->tag, src, ptr, objectbase, |
| tauBaseNonNull, tauAddressInRange, |
| tauElemTypeChecked)); |
| } else { |
| appendInst(instFactory->makeTauStRef((Modifier(Store_NoWriteBarrier)| |
| compressMod), |
| type->tag, src, ptr, objectbase, |
| tauBaseNonNull, tauAddressInRange, |
| tauElemTypeChecked)); |
| } |
| } |
| |
| void |
| IRBuilder::genStField(Type* type, Opnd* base, FieldDesc* fieldDesc,Opnd* src) { |
| assert (!fieldDesc->isStatic()); |
| |
| base = propagateCopy(base); |
| src = propagateCopy(src); |
| Opnd *tauBaseNonNull = genTauCheckNull(base); |
| Opnd *tauBaseTypeIsOk = genTauHasType(base, fieldDesc->getParentType()); |
| // Type *fieldType = fieldDesc->getFieldType(); |
| Opnd *tauStoredTypeIsOk = (type->isObject() |
| ? genTauHasType(src, type) |
| : genTauSafe()); // safe, not an object |
| if (irBuilderFlags.expandMemAddrs) { // do not expand ldField of stack values |
| Opnd *ptr = genLdFieldAddr(type, base, fieldDesc); |
| if (irBuilderFlags.insertWriteBarriers && src->getType()->isObject()) { |
| genTauStRef(type, base, ptr, src, |
| tauBaseNonNull, |
| tauBaseTypeIsOk, |
| tauStoredTypeIsOk); |
| } else { |
| genTauStInd(type, ptr, src, |
| tauBaseNonNull, |
| tauBaseTypeIsOk, |
| tauStoredTypeIsOk); |
| } |
| } else { |
| if (irBuilderFlags.insertWriteBarriers && |
| base->getType()->isValue()==false) { |
| appendInst(instFactory->makeTauStField((Modifier(Store_WriteBarrier)| |
| Modifier(AutoCompress_Yes)), |
| type->tag, src, base, |
| tauBaseNonNull, |
| tauBaseTypeIsOk, |
| tauStoredTypeIsOk, |
| fieldDesc)); |
| } else { |
| appendInst(instFactory->makeTauStField((Modifier(Store_NoWriteBarrier)| |
| Modifier(AutoCompress_Yes)), |
| type->tag, src, base, |
| tauBaseNonNull, |
| tauBaseTypeIsOk, |
| tauStoredTypeIsOk, |
| fieldDesc)); |
| } |
| } |
| } |
| |
| |
| void |
| IRBuilder::genStFieldWithResolve(Type* type, Opnd* base, ObjectType* enclClass, U_32 cpIdx, Opnd* src) { |
| base = propagateCopy(base); |
| src = propagateCopy(src); |
| Opnd *tauBaseNonNull = genTauCheckNull(base); |
| Opnd *tauBaseTypeIsOk = genTauSafe(); |
| Opnd *tauStoredTypeIsOk = (type->isObject() ? genTauHasType(src, type) : genTauSafe()); |
| assert(irBuilderFlags.expandMemAddrs); |
| Opnd *ptr = genLdFieldAddrWithResolve(type, base, enclClass, cpIdx, true); |
| if (irBuilderFlags.insertWriteBarriers && src->getType()->isObject()) { |
| genTauStRef(type, base, ptr, src, |
| tauBaseNonNull, |
| tauBaseTypeIsOk, |
| tauStoredTypeIsOk); |
| } else { |
| genTauStInd(type, ptr, src, |
| tauBaseNonNull, |
| tauBaseTypeIsOk, |
| tauStoredTypeIsOk); |
| } |
| } |
| |
| |
| void |
| IRBuilder::genStStaticWithResolve(Type* type, ObjectType* enclClass, U_32 cpIdx, Opnd* src) { |
| src = propagateCopy(src); |
| Opnd *tauOk = genTauSafe(); // address is always ok |
| Opnd *tauTypeIsOk = type->isObject() ? genTauHasType(src, type) : genTauSafe(); |
| assert(irBuilderFlags.expandMemAddrs); |
| Opnd* addr = genLdStaticAddrWithResolve(type, enclClass, cpIdx, true); |
| genTauStInd(type, addr, src, tauOk, tauOk, tauTypeIsOk); |
| return; |
| } |
| |
| void |
| IRBuilder::genStStatic(Type* type, FieldDesc* fieldDesc, Opnd* src) { |
| src = propagateCopy(src); |
| genInitType(fieldDesc->getParentType()); |
| Opnd *tauOk = genTauSafe(); // address is always ok |
| // Type *fieldType = fieldDesc->getFieldType(); |
| Opnd *tauTypeIsOk = (type->isObject() |
| ? genTauHasType(src, type) |
| : genTauSafe()); // safe, not an object |
| if (irBuilderFlags.expandMemAddrs) { |
| genTauStInd(type, genLdStaticAddr(type, fieldDesc), src, |
| tauOk, |
| tauOk, |
| tauTypeIsOk // safety may depend on a type check |
| ); |
| return; |
| } |
| if (irBuilderFlags.insertWriteBarriers) { |
| appendInst(instFactory->makeTauStStatic((Modifier(Store_WriteBarrier)| |
| Modifier(AutoCompress_Yes)), |
| type->tag, src, |
| tauTypeIsOk, |
| fieldDesc)); |
| } else { |
| appendInst(instFactory->makeTauStStatic((Modifier(Store_NoWriteBarrier)| |
| Modifier(AutoCompress_Yes)), |
| type->tag, src, |
| tauTypeIsOk, |
| fieldDesc)); |
| } |
| } |
| |
| void |
| IRBuilder::genStElem(Type* elemType, |
| Opnd* array, |
| Opnd* index, |
| Opnd* src, |
| Opnd* tauNullChecked, |
| Opnd* tauBaseTypeChecked, |
| Opnd* tauAddressInRange) { |
| array = propagateCopy(array); |
| src = propagateCopy(src); |
| index = propagateCopy(index); |
| |
| Opnd *tauElemTypeChecked = NULL; |
| if (elemType->isObject()) { |
| tauElemTypeChecked = genTauCheckElemType(array, src, tauNullChecked, |
| tauBaseTypeChecked); |
| } else { |
| tauElemTypeChecked = genTauSafe(); // src type is ok if non-object |
| } |
| if (irBuilderFlags.expandMemAddrs) { |
| Opnd *ptr = NULL; |
| if (tauNullChecked && tauAddressInRange) { |
| ptr = genLdElemAddrNoChecks(elemType, array, index); |
| } else { |
| ptr = genLdElemAddr(elemType, array, index); |
| } |
| if (irBuilderFlags.insertWriteBarriers && elemType->isObject()) { |
| genTauStRef(elemType, array, ptr, src, tauNullChecked, tauAddressInRange, |
| tauElemTypeChecked); |
| } else { |
| genTauStInd(elemType, ptr, src, tauNullChecked, tauAddressInRange, |
| tauElemTypeChecked); |
| } |
| } else { |
| if (irBuilderFlags.insertWriteBarriers) { |
| appendInst(instFactory->makeTauStElem((Modifier(Store_WriteBarrier)| |
| Modifier(AutoCompress_Yes)), |
| elemType->tag, src, array, index, |
| tauNullChecked, |
| tauAddressInRange, |
| tauElemTypeChecked)); |
| } else { |
| appendInst(instFactory->makeTauStElem((Modifier(Store_NoWriteBarrier)| |
| Modifier(AutoCompress_Yes)), |
| elemType->tag, src, array, index, |
| tauNullChecked, |
| tauAddressInRange, |
| tauElemTypeChecked)); |
| } |
| } |
| } |
| |
| void |
| IRBuilder::genStElem(Type* elemType, |
| Opnd* array, |
| Opnd* index, |
| Opnd* src) { |
| |
| array = propagateCopy(array); |
| src = propagateCopy(src); |
| index = propagateCopy(index); |
| |
| Opnd *tauNullChecked = NULL; |
| Opnd *tauAddressInRange = NULL; |
| Opnd *tauBaseTypeChecked = NULL; |
| |
| // prepare checks |
| tauNullChecked = genTauCheckNull(array); |
| tauBaseTypeChecked = genTauHasType(array, array->getType()); |
| Opnd *tauBoundsChecked = genTauCheckBounds(array, index, tauNullChecked); |
| tauAddressInRange = genTauAnd(tauBaseTypeChecked, tauBoundsChecked); |
| |
| genStElem(elemType,array,index,src,tauNullChecked,tauBaseTypeChecked,tauAddressInRange); |
| } |
| |
| |
| Opnd* |
| IRBuilder::genNewObj(Type* type) { |
| assert(type->isNamedType()); |
| Opnd* dst = createOpnd(type); |
| //FIXME class initialization must be done before allocating new object |
| appendInst(instFactory->makeNewObj(dst, type)); |
| genInitType(type->asNamedType()); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genNewObjWithResolve(ObjectType* enclClass, U_32 cpIndex) { |
| Opnd* clsOpnd = createTypeOpnd(enclClass); |
| Opnd* idxOpnd = genLdConstant((int)cpIndex); |
| Opnd** args = new (irManager->getMemoryManager()) Opnd*[2]; |
| args[0]=clsOpnd; |
| args[1]=idxOpnd; |
| Opnd* res = genVMHelperCall(VM_RT_NEWOBJ_WITHRESOLVE, typeManager->getUnresolvedObjectType(), 2, args); |
| return res; |
| } |
| |
| Opnd* |
| IRBuilder::genNewArrayWithResolve(NamedType* elemType, Opnd* numElems, ObjectType* enclClass, U_32 cpIndex) { |
| numElems = propagateCopy(numElems); |
| Opnd* clsOpnd = createTypeOpnd(enclClass); |
| Opnd* idxOpnd = genLdConstant((int)cpIndex); |
| Opnd** args = new (irManager->getMemoryManager()) Opnd*[3]; |
| args[0]=clsOpnd; |
| args[1]=idxOpnd; |
| args[2]=numElems; |
| Type* resType = typeManager->getArrayType(elemType); |
| Opnd* res = genVMHelperCall(VM_RT_NEWARRAY_WITHRESOLVE, resType, 3, args); |
| return res; |
| } |
| |
| Opnd* |
| IRBuilder::genNewArray(NamedType* elemType, Opnd* numElems) { |
| numElems = propagateCopy(numElems); |
| Opnd* dst = createOpnd(typeManager->getArrayType(elemType)); |
| appendInst(instFactory->makeNewArray(dst, numElems, elemType)); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genMultianewarray(NamedType* arrayType, |
| U_32 dimensions, |
| Opnd** numElems) { |
| NamedType* elemType = arrayType; |
| // create an array of arrays type |
| for (U_32 i=0; i<dimensions; i++) { |
| elemType = ((ArrayType*)elemType)->getElementType(); |
| } |
| Opnd* dst = createOpnd(arrayType); |
| appendInst(instFactory->makeNewMultiArray(dst, dimensions, numElems, elemType)); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genMultianewarrayWithResolve(NamedType* arrayType, |
| ObjectType* enclClass, |
| U_32 cpIndex, |
| U_32 dimensions, |
| Opnd** numElems) |
| { |
| Opnd* enclClsOpnd = createTypeOpnd(enclClass); |
| Opnd* idxOpnd = genLdConstant((int)cpIndex); |
| Opnd** args = new (irManager->getMemoryManager()) Opnd*[2]; |
| args[0] = enclClsOpnd; |
| args[1] = idxOpnd; |
| Opnd* clsOpnd = genVMHelperCall(VM_RT_INITIALIZE_CLASS_WITHRESOLVE, |
| typeManager->getUnmanagedPtrType(typeManager->getInt8Type()), |
| 2, args); |
| |
| size_t nArgs2 = 2+dimensions; |
| Opnd** args2 = new (irManager->getMemoryManager()) Opnd*[nArgs2]; |
| args2[0]=clsOpnd; |
| args2[1]=genLdConstant((int)dimensions); |
| // create an array of arrays type |
| for (U_32 i=0; i<dimensions; i++) { |
| args2[i+2]=numElems[dimensions-1-i]; |
| } |
| Opnd* dst = genVMHelperCall(VM_RT_MULTIANEWARRAY_RESOLVED, arrayType, (U_32)nArgs2, args2); |
| return dst; |
| } |
| |
| |
| void |
| IRBuilder::genMonitorEnter(Opnd* src) { |
| src = propagateCopy(src); |
| Opnd *tauNullChecked = genTauCheckNull(src); |
| appendInst(instFactory->makeTauMonitorEnter(src, tauNullChecked)); |
| } |
| |
| void |
| IRBuilder::genMonitorExit(Opnd* src) { |
| src = propagateCopy(src); |
| Opnd *tauNullChecked = genTauCheckNull(src); |
| appendInst(instFactory->makeTauMonitorExit(src, tauNullChecked)); |
| } |
| |
| Opnd* |
| IRBuilder::genLdLockAddr(Type* dstType, Opnd* obj) { |
| obj = propagateCopy(obj); |
| Opnd* dst = lookupHash(Op_LdLockAddr, obj); |
| if (dst) return dst; |
| |
| dst = createOpnd(dstType); |
| appendInst(instFactory->makeLdLockAddr(dst, obj)); |
| insertHash(Op_LdLockAddr, obj, dst->getInst()); |
| return dst; |
| } |
| |
| void |
| IRBuilder::genIncRecCount(Opnd* obj, Opnd *oldLock) { |
| obj = propagateCopy(obj); |
| oldLock = propagateCopy(oldLock); |
| appendInst(instFactory->makeLdLockAddr(obj, oldLock)); |
| } |
| |
| |
| Opnd* |
| IRBuilder::genBalancedMonitorEnter(Type* dstType, Opnd* src, Opnd *lockAddr) { |
| // src should already have been checked for null |
| src = propagateCopy(src); |
| lockAddr = propagateCopy(lockAddr); |
| Opnd *tauNullChecked = genTauCheckNull(src); |
| return genTauBalancedMonitorEnter(dstType, src, lockAddr, tauNullChecked); |
| } |
| |
| Opnd* |
| IRBuilder::genTauBalancedMonitorEnter(Type* dstType, Opnd* src, Opnd *lockAddr, |
| Opnd* tauNullChecked) { |
| // src should already have been checked for null |
| src = propagateCopy(src); |
| lockAddr = propagateCopy(lockAddr); |
| Opnd *dst = createOpnd(dstType); |
| appendInst(instFactory->makeTauBalancedMonitorEnter(dst, src, lockAddr, |
| tauNullChecked)); |
| return dst; |
| } |
| |
| void |
| IRBuilder::genBalancedMonitorExit(Opnd* src, Opnd *lockAddr, Opnd *oldValue) { |
| // src should already have been checked for null |
| src = propagateCopy(src); |
| appendInst(instFactory->makeBalancedMonitorExit(src, lockAddr, oldValue)); |
| } |
| |
| Opnd* |
| IRBuilder::genTauOptimisticBalancedMonitorEnter(Type* dstType, Opnd* src, |
| Opnd *lockAddr, |
| Opnd *tauNullChecked) { |
| // src should already have been checked for null |
| src = propagateCopy(src); |
| lockAddr = propagateCopy(lockAddr); |
| Opnd *dst = createOpnd(dstType); |
| appendInst(instFactory->makeTauOptimisticBalancedMonitorEnter(dst, src, |
| lockAddr, |
| tauNullChecked)); |
| return dst; |
| } |
| |
| void |
| IRBuilder::genMonitorEnterFence(Opnd* src) { |
| src = propagateCopy(src); |
| appendInst(instFactory->makeMonitorEnterFence(src)); |
| } |
| |
| void |
| IRBuilder::genMonitorExitFence(Opnd* src) { |
| src = propagateCopy(src); |
| appendInst(instFactory->makeMonitorExitFence(src)); |
| } |
| |
| void |
| IRBuilder::genTypeMonitorEnter(Type* type) { |
| appendInst(instFactory->makeTypeMonitorEnter(type)); |
| } |
| |
| void |
| IRBuilder::genTypeMonitorExit(Type* type) { |
| appendInst(instFactory->makeTypeMonitorExit(type)); |
| } |
| |
| |
| // type checking |
| // CastException (succeeds if argument is null, returns casted object) |
| Opnd* |
| IRBuilder::genCast(Opnd* src, Type* castType) { |
| src = propagateCopy(src); |
| Opnd* dst = lookupHash(Op_TauCast, src->getId(), castType->getId()); |
| if (dst) return dst; |
| |
| Opnd *tauCheckedCast = lookupHash(Op_TauCheckCast, src->getId(), castType->getId()); |
| if (!tauCheckedCast) { |
| Opnd *tauNullChecked = lookupHash(Op_TauCheckNull, src->getId()); |
| if (!tauNullChecked) { |
| tauNullChecked = genTauUnsafe(); |
| } |
| |
| tauCheckedCast = genTauCheckCast(src, tauNullChecked, castType); |
| } |
| |
| dst = genTauStaticCast(src, tauCheckedCast, castType); |
| insertHash(Op_TauCast, src->getId(), castType->getId(), dst->getInst()); |
| return dst; |
| } |
| |
| // type checking |
| // CastException (succeeds if argument is null, returns casted object) |
| Opnd* |
| IRBuilder::genCastWithResolve(Opnd* src, Type* type, ObjectType* enclClass, U_32 cpIndex) { |
| src = propagateCopy(src); |
| Opnd* dst = lookupHash(Op_VMHelperCall, OPCODE_CHECKCAST, src->getId(), cpIndex); |
| if (dst) return dst; |
| |
| Opnd** args = new (irManager->getMemoryManager()) Opnd*[3]; |
| args[0] = createTypeOpnd(enclClass); |
| args[1] = genLdConstant((int)cpIndex); |
| args[2] = src; |
| dst = genVMHelperCall(VM_RT_CHECKCAST_WITHRESOLVE, type, 3, args); |
| insertHash(Op_VMHelperCall, OPCODE_CHECKCAST, src->getId(), cpIndex, dst->getInst()); |
| return dst; |
| } |
| |
| |
| Opnd* |
| IRBuilder::genTauCheckCast(Opnd* src, Opnd *tauNullChecked, Type* castType) { |
| src = propagateCopy(src); |
| tauNullChecked = propagateCopy(tauNullChecked); |
| Opnd* dst = lookupHash(Op_TauCheckCast, src->getId(), castType->getId()); |
| if (dst) return dst; |
| |
| if (irBuilderFlags.doSimplify) { |
| bool alwaysThrows = false; |
| dst = simplifier->simplifyTauCheckCast(src, tauNullChecked, castType, alwaysThrows); |
| if (dst) { |
| return dst; |
| } |
| } |
| |
| dst = createOpnd(typeManager->getTauType()); |
| appendInst(instFactory->makeTauCheckCast(dst, src, tauNullChecked, castType)); |
| insertHash(Op_TauCheckCast, src->getId(), castType->getId(), dst->getInst()); |
| return dst; |
| } |
| |
| // returns src if src is an instance of type, NULL otherwise |
| Opnd* |
| IRBuilder::genAsType(Opnd* src, Type* type) { |
| if (type->isUserValue()) { |
| assert(0); |
| } |
| src = propagateCopy(src); |
| |
| Opnd* tauCheckedNull = genTauUnsafe(); |
| |
| Opnd* dst = lookupHash(Op_TauAsType, src->getId(), tauCheckedNull->getId(), type->getId()); |
| if (dst) return dst; |
| |
| if (irBuilderFlags.doSimplify) { |
| dst = simplifier->simplifyTauAsType(src, tauCheckedNull, type); |
| if (dst) return dst; |
| } |
| dst = createOpnd(type); |
| appendInst(instFactory->makeTauAsType(dst, src, tauCheckedNull, type)); |
| insertHash(Op_TauAsType, src->getId(), tauCheckedNull->getId(), type->getId(), dst->getInst()); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genInstanceOf(Opnd* src, Type* type) { |
| src = propagateCopy(src); |
| |
| Opnd *tauNullChecked = genTauUnsafe(); |
| |
| Opnd* dst = lookupHash(Op_TauInstanceOf, src->getId(), |
| tauNullChecked->getId(), type->getId()); |
| if (dst) return dst; |
| |
| if (irBuilderFlags.doSimplify) { |
| dst = simplifier->simplifyTauInstanceOf(src, tauNullChecked, type); |
| if (dst) return dst; |
| } |
| |
| dst = createOpnd(typeManager->getInt32Type()); |
| appendInst(instFactory->makeTauInstanceOf(dst, src, tauNullChecked, type)); |
| insertHash(Op_TauInstanceOf, src->getId(), type->getId(), |
| tauNullChecked->getId(), dst->getInst()); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genInstanceOfWithResolve(Opnd* src, ObjectType* enclClass, U_32 cpIndex) { |
| src = propagateCopy(src); |
| |
| Opnd* dst = lookupHash(Op_VMHelperCall, OPCODE_INSTANCEOF, src->getId(), cpIndex); |
| if (dst) { |
| return dst; |
| } |
| |
| Opnd** args = new (irManager->getMemoryManager()) Opnd*[3]; |
| args[0] = createTypeOpnd(enclClass); |
| args[1] = genLdConstant((int)cpIndex); |
| args[2] = src; |
| dst = genVMHelperCall(VM_RT_INSTANCEOF_WITHRESOLVE, typeManager->getInt32Type(), 3, args); |
| insertHash(Op_VMHelperCall, OPCODE_INSTANCEOF, src->getId(), cpIndex, dst->getInst()); |
| return dst; |
| } |
| |
| |
| //----------------------------------------------------------------------------- |
| // |
| // Private helper methods for generating instructions |
| // |
| //----------------------------------------------------------------------------- |
| Opnd* |
| IRBuilder::propagateCopy(Opnd* opnd) { |
| return simplifier->propagateCopy(opnd); |
| } |
| |
| Opnd* IRBuilder::createOpnd(Type* type) { |
| if (type->tag == Type::Void) |
| return OpndManager::getNullOpnd(); |
| return opndManager->createSsaTmpOpnd(type); |
| } |
| |
| PiOpnd* IRBuilder::createPiOpnd(Opnd *org) { |
| return opndManager->createPiOpnd(org); |
| } |
| |
| Opnd* IRBuilder::genTauCheckNull(Opnd* base) { |
| base = propagateCopy(base); |
| if (! irBuilderFlags.expandNullChecks) { |
| assert(0); // not expanding them is not compatible with taus |
| return base; |
| } |
| |
| Opnd* res = lookupHash(Op_TauCheckNull, base); |
| if (res) return res; |
| |
| // Not advisable to turn off simplification of checknull because |
| // IRBuilder calls genTauCheckNull redundantly many times |
| bool alwaysThrows = false; |
| res = simplifier->simplifyTauCheckNull(base, alwaysThrows); |
| if (res && (res->getInst()->getOpcode() != Op_TauUnsafe)) return res; |
| Opnd* dst = createOpnd(typeManager->getTauType()); |
| Inst *inst = appendInst(instFactory->makeTauCheckNull(dst, base)); |
| insertHash(Op_TauCheckNull, base, inst); |
| |
| // We can make the type init for the base object available here |
| Type* baseType = base->getType(); |
| insertHash(Op_InitType, baseType->getId(), inst); |
| return dst; |
| } |
| |
| Opnd* IRBuilder::genTauCheckZero(Opnd* src) { |
| src = propagateCopy(src); |
| |
| |
| Opnd* res = lookupHash(Op_TauCheckZero, src); |
| if (res) return res; |
| |
| bool alwaysThrows = false; |
| res = simplifier->simplifyTauCheckZero(src, alwaysThrows); |
| if (res && (res->getInst()->getOpcode() != Op_TauUnsafe)) return res; |
| |
| Opnd* dst = createOpnd(typeManager->getTauType()); |
| appendInst(instFactory->makeTauCheckZero(dst, src)); |
| insertHash(Op_TauCheckZero, src, dst->getInst()); |
| return dst; |
| } |
| |
| Opnd *IRBuilder::genTauCheckDivOpnds(Opnd* src1, Opnd *src2) { |
| src1 = propagateCopy(src1); |
| src2 = propagateCopy(src2); |
| |
| |
| Opnd* res = lookupHash(Op_TauCheckDivOpnds, src1, src2); |
| if (res) return res; |
| |
| bool alwaysThrows = false; |
| res = simplifier->simplifyTauCheckDivOpnds(src1, src2, alwaysThrows); |
| if (res && (res->getInst()->getOpcode() != Op_TauUnsafe)) return res; |
| |
| Opnd* dst = createOpnd(typeManager->getTauType()); |
| Inst *inst = appendInst(instFactory->makeTauCheckDivOpnds(dst, src1, src2)); |
| insertHash(Op_TauCheckDivOpnds, src1, src2, inst); |
| return dst; |
| } |
| |
| Opnd *IRBuilder::genTauCheckBounds(Opnd* array, Opnd* index, Opnd *tauNullChecked) { |
| // just to allow limit studies, omit all bounds checks |
| // if command-line flag is given |
| if (irBuilderFlags.suppressCheckBounds) |
| return genTauUnsafe(); |
| |
| array = propagateCopy(array); |
| index = propagateCopy(index); |
| |
| // we also hash operation with array as the opnd |
| Opnd* res = lookupHash(Op_TauCheckBounds, array, index); |
| if (res) return res; |
| |
| Opnd *tauArrayTypeChecked = genTauHasType(array, array->getType()); |
| Opnd* arrayLen = genTauArrayLen(typeManager->getInt32Type(), Type::Int32, array, |
| tauNullChecked, tauArrayTypeChecked); |
| |
| Opnd* dst = genTauCheckBounds(arrayLen, index); |
| // we also hash operation with array as the opnd |
| insertHash(Op_TauCheckBounds, array, index, dst->getInst()); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genTauCheckElemType(Opnd* array, Opnd* src, Opnd *tauNullChecked, |
| Opnd *tauIsArray) { |
| if (! irBuilderFlags.expandElemTypeChecks) |
| return genTauUnsafe(); |
| |
| array = propagateCopy(array); |
| src = propagateCopy(src); |
| Opnd* res = lookupHash(Op_TauCheckElemType, array, src); |
| if (res) return res; |
| |
| if (irBuilderFlags.doSimplify) { |
| bool alwaysThrows = false; |
| res = simplifier->simplifyTauCheckElemType(array, src, alwaysThrows); |
| if (res && (res->getInst()->getOpcode() != Op_TauUnsafe)) return res; |
| } |
| Opnd* dst = createOpnd(typeManager->getTauType()); |
| Inst* inst = appendInst(instFactory->makeTauCheckElemType(dst, array, src, |
| tauNullChecked, |
| tauIsArray)); |
| insertHash(Op_TauCheckElemType, array, src, inst); |
| return dst; |
| } |
| |
| Opnd * |
| IRBuilder::genTauCheckBounds(Opnd* ub, Opnd *index) { |
| index = propagateCopy(index); |
| ub = propagateCopy(ub); |
| |
| Opnd* dst = lookupHash(Op_TauCheckBounds, ub, index); |
| if (dst) return dst; |
| |
| if (irBuilderFlags.doSimplify) { |
| bool alwaysThrows = false; |
| dst = simplifier->simplifyTauCheckBounds(ub, index, alwaysThrows); |
| } |
| |
| if (!(dst && (dst->getInst()->getOpcode() != Op_TauUnsafe))) { |
| // need to create one |
| dst = createOpnd(typeManager->getTauType()); |
| appendInst(instFactory->makeTauCheckBounds(dst, ub, index)); |
| } |
| insertHash(Op_TauCheckBounds, ub, index, dst->getInst()); |
| return dst; |
| } |
| |
| Opnd * |
| IRBuilder::genCheckFinite(Type *dstType, Opnd* src) { |
| assert(dstType == src->getType()); |
| (void) genTauCheckFinite(src); |
| return src; |
| } |
| |
| Opnd * |
| IRBuilder::genTauCheckFinite(Opnd* src) { |
| src = propagateCopy(src); |
| Opnd* dst = lookupHash(Op_TauCheckFinite, src); |
| if (dst) return dst; |
| |
| if (irBuilderFlags.doSimplify) { |
| bool alwaysThrows = false; |
| dst = simplifier->simplifyTauCheckFinite(src, alwaysThrows); |
| if (dst && (dst->getInst()->getOpcode() != Op_TauUnsafe)) return dst; |
| } |
| |
| dst = createOpnd(typeManager->getTauType()); |
| appendInst(instFactory->makeTauCheckFinite(dst, src)); |
| insertHash(Op_TauCheckFinite, src, dst->getInst()); |
| return dst; |
| } |
| |
| //----------------------------------------------------------------------------- |
| // |
| // Methods for CSE hashing |
| // |
| //----------------------------------------------------------------------------- |
| Opnd* IRBuilder::lookupHash(U_32 opc) { |
| if (! irBuilderFlags.doCSE) |
| return NULL; |
| Inst* inst = cseHashTable->lookup(opc); |
| if (inst) |
| return inst->getDst(); |
| else |
| return NULL; |
| } |
| |
| Opnd* IRBuilder::lookupHash(U_32 opc, U_32 op) { |
| if (! irBuilderFlags.doCSE) |
| return NULL; |
| Inst* inst = cseHashTable->lookup(opc, op); |
| if (inst) |
| return inst->getDst(); |
| else |
| return NULL; |
| } |
| |
| Opnd* IRBuilder::lookupHash(U_32 opc, U_32 op1, U_32 op2) { |
| if (! irBuilderFlags.doCSE) |
| return NULL; |
| Inst* inst = cseHashTable->lookup(opc, op1, op2); |
| if (inst) |
| return inst->getDst(); |
| else |
| return NULL; |
| } |
| |
| Opnd* IRBuilder::lookupHash(U_32 opc, U_32 op1, U_32 op2, U_32 op3) { |
| if (! irBuilderFlags.doCSE) |
| return NULL; |
| Inst* inst = cseHashTable->lookup(opc, op1, op2, op3); |
| if (inst) |
| return inst->getDst(); |
| else |
| return NULL; |
| } |
| |
| void IRBuilder::insertHash(U_32 opc, Inst* inst) { |
| if (! irBuilderFlags.doCSE) |
| return; |
| cseHashTable->insert(opc, inst); |
| } |
| |
| void IRBuilder::insertHash(U_32 opc, U_32 op1, Inst* inst) { |
| if (! irBuilderFlags.doCSE) |
| return; |
| cseHashTable->insert(opc, op1, inst); |
| } |
| |
| void IRBuilder::insertHash(U_32 opc, U_32 op1, U_32 op2, Inst* inst) { |
| if (! irBuilderFlags.doCSE) |
| return; |
| cseHashTable->insert(opc, op1, op2, inst); |
| } |
| |
| void IRBuilder::insertHash(U_32 opc, U_32 op1, U_32 op2, U_32 op3, |
| Inst* inst) { |
| if (! irBuilderFlags.doCSE) |
| return; |
| cseHashTable->insert(opc, op1, op2, op3, inst); |
| } |
| |
| // tau instructions |
| Opnd* |
| IRBuilder::genTauSafe() { |
| Opnd* dst = lookupHash(Op_TauSafe); |
| if (dst) return dst; |
| |
| dst = createOpnd(typeManager->getTauType()); |
| appendInst(instFactory->makeTauSafe(dst)); |
| |
| insertHash(Op_TauSafe, dst->getInst()); |
| return dst; |
| } |
| |
| // tau instructions |
| Opnd* |
| IRBuilder::genTauMethodSafe() { |
| Opnd* dst = tauMethodSafeOpnd; |
| if (dst) return dst; |
| |
| dst = createOpnd(typeManager->getTauType()); |
| Inst *inst = instFactory->makeTauPoint(dst); |
| |
| Node *head = flowGraph->getEntryNode(); |
| Inst *entryLabel = (Inst*)head->getFirstInst(); |
| // first search for one already there |
| Inst *where = entryLabel->getNextInst(); |
| while (where != NULL) { |
| if (where->getOpcode() != Op_DefArg) { |
| break; |
| } |
| where = where->getNextInst(); |
| } |
| // insert before where |
| inst->insertBefore(where); |
| |
| tauMethodSafeOpnd = dst; |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genTauUnsafe() { |
| Operation operation(Op_TauUnsafe, Type::Tau, Modifier()); |
| Opnd* dst = lookupHash(Op_TauUnsafe); |
| if (dst) return dst; |
| |
| dst = createOpnd(typeManager->getTauType()); |
| appendInst(instFactory->makeTauUnsafe(dst)); |
| |
| insertHash(Op_TauUnsafe, dst->getInst()); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genTauStaticCast(Opnd *src, Opnd *tauCheckedCast, Type *castType) { |
| Operation operation(Op_TauStaticCast, castType->tag, Modifier()); |
| U_32 hashcode = operation.encodeForHashing(); |
| Opnd* dst = lookupHash(hashcode, src->getId(), tauCheckedCast->getId(), castType->getId()); |
| if (dst) return dst; |
| |
| dst = createOpnd(castType); |
| appendInst(instFactory->makeTauStaticCast(dst, src, tauCheckedCast, castType)); |
| |
| insertHash(hashcode, src->getId(), tauCheckedCast->getId(), castType->getId(), dst->getInst()); |
| Operation hasTypeOperation(Op_TauHasType, castType->tag, Modifier()); |
| U_32 hasTypeHashcode = hasTypeOperation.encodeForHashing(); |
| insertHash(hasTypeHashcode, src->getId(), castType->getId(), tauCheckedCast->getId(), |
| dst->getInst()); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genTauHasType(Opnd *src, Type *castType) { |
| Operation operation(Op_TauHasType, castType->tag, Modifier()); |
| U_32 hashcode = operation.encodeForHashing(); |
| Opnd* dst = lookupHash(hashcode, src->getId(), castType->getId()); |
| if (dst) return dst; |
| |
| dst = createOpnd(typeManager->getTauType()); |
| appendInst(instFactory->makeTauHasType(dst, src, castType)); |
| |
| insertHash(hashcode, src->getId(), castType->getId(), dst->getInst()); |
| return dst; |
| } |
| |
| Opnd* IRBuilder::genTauHasTypeWithConv(Opnd **srcPtr, Type *hasType) { |
| Opnd* src = srcPtr[0]; |
| Opnd* res = genTauHasType(src, hasType); |
| Type* srcType = src->getType(); |
| if (srcType->isUnresolvedType()) { |
| //change opnd type in case if unresolved |
| Modifier mod = Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No); |
| Opnd* newSrc = genConv(hasType, hasType->tag, mod, src); |
| srcPtr[0] = newSrc; |
| } |
| return res; |
| } |
| |
| Opnd* |
| IRBuilder::genTauHasExactType(Opnd *src, Type *castType) { |
| Operation operation(Op_TauHasExactType, castType->tag, Modifier()); |
| U_32 hashcode = operation.encodeForHashing(); |
| Opnd* dst = lookupHash(hashcode, src->getId(), castType->getId()); |
| if (dst) return dst; |
| |
| dst = createOpnd(typeManager->getTauType()); |
| appendInst(instFactory->makeTauHasExactType(dst, src, castType)); |
| |
| insertHash(hashcode, src->getId(), castType->getId(), dst->getInst()); |
| return dst; |
| } |
| |
| Opnd* |
| IRBuilder::genTauIsNonNull(Opnd *src) { |
| U_32 hashcode = Op_TauCheckNull; |
| Opnd* dst = lookupHash(hashcode, src->getId()); |
| if (dst) return dst; |
| |
| dst = createOpnd(typeManager->getTauType()); |
| appendInst(instFactory->makeTauIsNonNull(dst, src)); |
| |
| insertHash(hashcode, src->getId(), dst->getInst()); |
| |
| // We can also make the type init for the base object available here |
| Type* baseType = src->getType(); |
| insertHash(Op_InitType, baseType->getId(), dst->getInst()); |
| |
| return dst; |
| } |
| |
| |
| Opnd* |
| IRBuilder::genTauAnd(Opnd *src1, Opnd *src2) { |
| if (src1->getId() > src2->getId()) { |
| Opnd *tmp = src1; |
| src1 = src2; |
| src2 = tmp; |
| } |
| Opnd* dst = lookupHash(Op_TauAnd, src1, src2); |
| if (dst) return dst; |
| |
| dst = createOpnd(typeManager->getTauType()); |
| Opnd* srcs[2] = { src1, src2 }; |
| appendInst(instFactory->makeTauAnd(dst, 2, srcs)); |
| |
| insertHash(Op_TauAnd, src1->getId(), src2->getId(), dst->getInst()); |
| return dst; |
| } |
| |
| |
| Inst* IRBuilder::getLastGeneratedInst() { |
| return (Inst*)currentLabel->getNode()->getLastInst(); |
| } |
| |
| } //namespace Jitrino |