| /* |
| * 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 |
| * @version $Revision: 1.31.16.4 $ |
| * |
| */ |
| |
| |
| #include "Opcode.h" |
| #include "Opnd.h" |
| #include "Type.h" |
| #include "Inst.h" |
| #include "BitSet.h" |
| #include "Log.h" |
| #include "optimizer.h" |
| #include "simplifier.h" |
| #include "constantfolder.h" |
| #include "deadcodeeliminator.h" |
| #include "optarithmetic.h" |
| #include "reassociate.h" |
| #include "irmanager.h" |
| #include "CompilationContext.h" |
| |
| #include "FlowGraph.h" |
| |
| #include <float.h> |
| #include <math.h> |
| #include "PlatformDependant.h" |
| |
| namespace Jitrino { |
| /* |
| * Implemented algorithms are similar to the ones described in |
| * [T.Granlund and P.L.Montgomery. Division by Invariant Integers using |
| * Multiplication. PLDI, 1994], [S.Muchnick. Advanced Compiler Design and |
| * Implementation. Morgan Kaufmann, San Francisco, CA, 1997]. |
| */ |
| |
| |
| DEFINE_SESSION_ACTION(SimplificationPass, simplify, "Perform simplification pass"); |
| void |
| SimplificationPass::_run(IRManager& irm) { |
| SimplifierWithInstFactory simplifier(irm, false); |
| simplifier.simplifyControlFlowGraph(); |
| } |
| |
| DEFINE_SESSION_ACTION(LateSimplificationPass, latesimplify, "Simplification + Constant Mul/Div Optimization"); |
| |
| void |
| LateSimplificationPass::_run(IRManager& irm) { |
| SimplifierWithInstFactory simplifier(irm, true); |
| simplifier.simplifyControlFlowGraph(); |
| } |
| |
| //----------------------------------------------------------------------------- |
| // Utilities for querying properties of opnds |
| //----------------------------------------------------------------------------- |
| static inline bool isNeg(Inst* inst) { |
| return inst->getOpcode() == Op_Neg; |
| } |
| static inline bool isNeg(Opnd* opnd) { |
| return isNeg(opnd->getInst()); |
| } |
| static inline bool isAdd(Inst* inst) { |
| return inst->getOpcode() == Op_Add; |
| } |
| static inline bool isAdd(Opnd* opnd) { |
| return isAdd(opnd->getInst()); |
| } |
| static inline bool isSub(Inst* inst) { |
| return inst->getOpcode() == Op_Sub; |
| } |
| static inline bool isSub(Opnd* opnd) { |
| return isSub(opnd->getInst()); |
| } |
| |
| static inline bool isAddWithConstant(Inst* inst) { |
| return (inst->getOpcode() == Op_Add && ConstantFolder::hasConstant(inst)); |
| } |
| |
| static inline bool isSubWithConstant(Inst* inst) { |
| return (inst->getOpcode() == Op_Sub && ConstantFolder::hasConstant(inst)); |
| } |
| |
| static inline bool isMultiplyByConstant(Inst* inst) { |
| return (inst->getOpcode() == Op_Mul && ConstantFolder::hasConstant(inst)); |
| } |
| |
| static inline bool isTauDivByConstant(Inst* inst) { |
| return (inst->getOpcode() == Op_TauDiv && |
| ConstantFolder::isConstant(inst->getSrc(1))); |
| } |
| |
| static inline bool isCopy(Inst* inst) { |
| return (inst->getOpcode() == Op_Copy); |
| } |
| |
| static Opnd* |
| getArraySize(Opnd* arrayBase) { |
| if (arrayBase->getType()->isArrayType() == false) |
| return NULL; |
| Inst* inst = arrayBase->getInst(); |
| if (inst->getOpcode() == Op_NewArray) { |
| return inst->getSrc(0); |
| } |
| return NULL; |
| } |
| |
| bool |
| Simplifier::isNonNullObject(Opnd* opnd) { |
| Inst* inst = opnd->getInst(); |
| switch (inst->getOpcode()) { |
| case Op_NewObj: case Op_NewArray: case Op_NewMultiArray: |
| case Op_LdRef: case Op_Catch: |
| return true; |
| default: |
| return false; |
| } |
| } |
| |
| bool |
| Simplifier::isNonNullParameter(Opnd* opnd) { |
| Inst* inst = opnd->getInst(); |
| if (inst->getOpcode() == Op_DefArg) { |
| return (inst->getDefArgModifier() == NonNullThisArg); |
| } |
| return false; |
| } |
| |
| bool |
| Simplifier::isNullObject(Opnd* opnd) { |
| return (opnd->getType()->isObject() && |
| opnd->getInst()->getOpcode() == Op_LdConstant); |
| } |
| |
| bool |
| Simplifier::isExactType(Opnd* opnd) { |
| Type* type = opnd->getType(); |
| if (type->isObject() && ((ObjectType*)type)->isFinalClass()) |
| return true; |
| Inst* inst = opnd->getInst(); |
| switch (inst->getOpcode()) { |
| case Op_NewObj: case Op_NewArray: case Op_NewMultiArray: |
| case Op_LdRef: |
| return true; |
| case Op_DefArg: |
| return (inst->getDefArgModifier() == SpecializedToExactType); |
| default: |
| return false; |
| } |
| } |
| //----------------------------------------------------------------------------- |
| // Simplifier class |
| //----------------------------------------------------------------------------- |
| Simplifier::Simplifier(IRManager& irm, bool latePass, |
| Reassociate *reassociate0) |
| : irManager(irm), flowGraph(irm.getFlowGraph()), |
| isLate(latePass), theReassociate(reassociate0) |
| { |
| } |
| |
| Inst* |
| Simplifier::optimizeInst(Inst* inst) { |
| // first copy propagate all sources of the instruction |
| DeadCodeEliminator::copyPropagate(inst); |
| // then simplify |
| return dispatch(inst); |
| } |
| |
| // fold unary operation |
| // returns NULL if no fold possible |
| // should always succeed on Int32/Int64 values |
| Opnd* |
| Simplifier::fold(Opcode op, Type* type, ConstInst *srcInst, bool is_signed) { |
| ConstInst::ConstValue res; |
| if (ConstantFolder::foldConstant(type->tag, op, srcInst->getValue(), res)) { |
| if (type->tag == Type::Int32) { |
| return genLdConstant(res.i4)->getDst(); |
| } else if (type->tag == Type::Int64) { |
| return genLdConstant(res.i8)->getDst(); |
| } else if (type->tag == Type::Single) { |
| return genLdConstant((float)res.s)->getDst(); |
| } else if (type->tag == Type::Double) { |
| return genLdConstant((double)res.d)->getDst(); |
| } else { |
| assert(0); |
| } |
| } |
| return NULL; |
| } |
| |
| // fold binary operation |
| // should always succeed on add/sub/mul of Int32/Int64 values |
| // returns NULL if no fold possible |
| Opnd* |
| Simplifier::fold(Opcode op, Type* type, ConstInst *srcInst1, ConstInst *srcInst2, |
| bool is_signed) { |
| ConstInst::ConstValue res; |
| if (ConstantFolder::foldConstant(type->tag, |
| op, |
| srcInst1->getValue(), |
| srcInst2->getValue(), |
| res, |
| is_signed)) { |
| if (type->tag == Type::Int32) { |
| return genLdConstant(res.i4)->getDst(); |
| } else if (type->tag == Type::Int64) { |
| return genLdConstant(res.i8)->getDst(); |
| } else if (type->tag == Type::Single) { |
| return genLdConstant((float)res.s)->getDst(); |
| } else if (type->tag == Type::Double) { |
| return genLdConstant((double)res.d)->getDst(); |
| } else { |
| assert(0); |
| } |
| } |
| return NULL; |
| } |
| |
| // fold comparison operation |
| // returns NULL if no fold possible |
| // apparently, destination will always be Int32 (or acceptable to represent as) |
| Opnd* |
| Simplifier::foldComparison(ComparisonModifier mod, |
| Type::Tag cmpType, |
| ConstInst* srcInst1, |
| ConstInst* srcInst2) { |
| ConstInst::ConstValue res; |
| if (ConstantFolder::foldCmp(cmpType, mod, |
| srcInst1->getValue(), srcInst2->getValue(), |
| res)) { |
| return genLdConstant(res.i4)->getDst(); |
| } |
| return NULL; |
| } |
| |
| // c1 + (c2 + s) -> (c1+c2) + s |
| // addInst must be add with constant operand, |
| // and same type as given. |
| Opnd* |
| Simplifier::foldConstByAddingToAddWithConstant(Type* type, |
| ConstInst* constInst, |
| Inst* addInst) { |
| // Note: types of the 2 ops must be the same |
| assert(type->tag == addInst->getType()); |
| |
| ConstInst* otherConstInst; |
| Opnd* nonConstSrc; |
| if (ConstantFolder::isConstant(addInst->getSrc(0))) { |
| // C + s |
| otherConstInst = addInst->getSrc(0)->getInst()->asConstInst(); |
| nonConstSrc = addInst->getSrc(1); |
| } else { |
| // s + C |
| otherConstInst = addInst->getSrc(1)->getInst()->asConstInst(); |
| nonConstSrc = addInst->getSrc(0); |
| } |
| // c1+c2 |
| Opnd* constSrc = fold(Op_Add, type, constInst, otherConstInst, true); |
| // (c1+c2) + s |
| return genAdd(type, Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No), constSrc, nonConstSrc)->getDst(); |
| } |
| |
| // c1 + (c2 - s) -> (c1+c2) - s |
| // c1 + (s - c2) -> (c1-c2) + s |
| // subInst must be subtract with constant operand, |
| // and type same as given. |
| Opnd* |
| Simplifier::foldConstByAddingToSubWithConstant(Type* type, |
| ConstInst* constInst, |
| Inst* subInst) { |
| // Note: types of the 2 ops must be the same |
| assert(type->tag == subInst->getType()); |
| |
| ConstInst* otherConstInst; |
| Opnd* nonConstSrc; |
| if (ConstantFolder::isConstant(subInst->getSrc(0))) { |
| // C2 - s |
| otherConstInst = subInst->getSrc(0)->getInst()->asConstInst(); |
| nonConstSrc = subInst->getSrc(1); |
| // (C1+C2) |
| Opnd* foldedConst = fold(Op_Add, type, constInst, otherConstInst, true); |
| // (C1+C2) - s |
| return genSub(type, Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No), foldedConst, nonConstSrc)->getDst(); |
| } else { |
| // s - C2 |
| nonConstSrc = subInst->getSrc(0); |
| otherConstInst = subInst->getSrc(1)->getInst()->asConstInst(); |
| // (C1 - C2) |
| Opnd* foldedConst = fold(Op_Sub, type, constInst, otherConstInst, true); |
| // s + (C1 - C2) |
| return genAdd(type, Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No), nonConstSrc, foldedConst)->getDst(); |
| } |
| } |
| |
| // c1 * (c2 + s) -> c1*c2 + (c1 * s) |
| // addInst must be an add with constant operand, |
| // and type same as is given. |
| // this is only signed multiply. |
| Opnd* |
| Simplifier::foldConstMultiplyByAddWithConstant(Type* type, |
| ConstInst* constInst, |
| Inst* addInst) { |
| // Note: types of the 2 ops must be the same |
| assert(type->tag == addInst->getType()); |
| ConstInst* otherConstInst; |
| |
| Opnd* nonConstSrc; |
| if (ConstantFolder::isConstant(addInst->getSrc(0))) { |
| // c2 + s |
| otherConstInst = addInst->getSrc(0)->getInst()->asConstInst(); |
| nonConstSrc = addInst->getSrc(1); |
| } else { |
| // s + c2 |
| otherConstInst = addInst->getSrc(1)->getInst()->asConstInst(); |
| nonConstSrc = addInst->getSrc(0); |
| } |
| // c1 * c2 |
| Opnd* constSrc = fold(Op_Mul, type, constInst, otherConstInst, true); |
| // c1 * s |
| Opnd* finalMulByConst = genMul(type, Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No), constInst->getDst(), |
| nonConstSrc)->getDst(); |
| return genAdd(type, Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No), constSrc, finalMulByConst)->getDst(); |
| } |
| |
| // c1 * (c2 - s) -> (c1*c2) - (c1*s) |
| // c1 * (s - c2) -> (c1*s) + -(c1*c2) |
| // subInst must be a subtract with constant src, |
| // and same type as is given. |
| // should probably only be used with int type. |
| Opnd* |
| Simplifier::foldConstMultiplyBySubWithConstant(Type* type, |
| ConstInst* constInst, // c1 |
| Inst* subInst) { |
| // Note: types of the 2 ops must be the same |
| assert(type->tag == subInst->getType()); |
| |
| if (ConstantFolder::isConstant(subInst->getSrc(0))) { |
| // c2 - s |
| ConstInst* otherConstInst = |
| subInst->getSrc(0)->getInst()->asConstInst(); // c2 |
| Opnd *nonConstSrc = subInst->getSrc(1); // s |
| // (c1 * c2) |
| Opnd* foldedConst = fold(Op_Mul, type, constInst, |
| otherConstInst, true); |
| // -c1 |
| Opnd* negC1 = fold(Op_Neg, type, constInst, true); |
| // (-c1) * s |
| Opnd* finalMulByConst = genMul(type, Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No), negC1, |
| nonConstSrc)->getDst(); |
| // (c1*c2) + (-c1)*s |
| return genAdd(type, Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No), |
| foldedConst, finalMulByConst)->getDst(); |
| } else { |
| // s - c2 |
| Opnd *nonConstSrc = subInst->getSrc(0); // s |
| ConstInst* otherConstInst = |
| subInst->getSrc(1)->getInst()->asConstInst(); // c2 |
| Opnd* negFoldedConst; // -(c1 * c2) |
| { // avoid creating a useless instr for c1*c2 |
| ConstInst::ConstValue res; // c1*c2 |
| #ifndef NDEBUG |
| bool foldres = |
| #endif |
| ConstantFolder::foldConstant(type->tag, Op_Mul, |
| constInst->getValue(), // c1 |
| otherConstInst->getValue(), // c2 |
| res, |
| true); |
| assert(foldres); |
| ConstInst::ConstValue negRes; // -(c1*c2) |
| #ifndef NDEBUG |
| foldres = |
| #endif |
| ConstantFolder::foldConstant(type->tag, Op_Neg, res, negRes); |
| assert(foldres); |
| if (type->tag == Type::Int32) { |
| negFoldedConst = genLdConstant(negRes.i4)->getDst(); |
| } else if (type->tag == Type::Int64) { |
| negFoldedConst = genLdConstant(negRes.i8)->getDst(); |
| } else { |
| negFoldedConst = 0; |
| assert(0); |
| } |
| } |
| // c1*s |
| Opnd* finalMulByConst = genMul(type, Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No), |
| constInst->getDst(), |
| nonConstSrc)->getDst(); |
| // (-(c1*c2)) + c1*s |
| return genAdd(type, Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No), |
| negFoldedConst, |
| finalMulByConst)->getDst(); |
| } |
| } |
| |
| // c1*(c2*s) -> s * (c1*c2) |
| // mulInst must be a multiply by constant, with getType()==type |
| // should probably only be used with int type. |
| Opnd* |
| Simplifier::foldConstMultiplyByMulWithConstant(Type* type, |
| ConstInst* constInst, |
| Inst* mulInst) { |
| // Note: types of the 2 ops must be the same |
| assert(type->tag == mulInst->getType()); |
| |
| ConstInst::ConstValue v1 = constInst->getValue(); |
| ConstInst* otherConstInst; |
| Opnd* nonConstSrc; |
| if (ConstantFolder::isConstant(mulInst->getSrc(0))) { |
| // C2 * s |
| otherConstInst = mulInst->getSrc(0)->getInst()->asConstInst(); |
| nonConstSrc = mulInst->getSrc(1); |
| } else { |
| // s * C2 |
| otherConstInst = mulInst->getSrc(1)->getInst()->asConstInst(); |
| nonConstSrc = mulInst->getSrc(0); |
| } |
| Opnd* constSrc = fold(Op_Mul, type, constInst, otherConstInst, true); |
| return genMul(type, Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No), constSrc, nonConstSrc)->getDst(); |
| } |
| |
| // mulInst must be a multiply by constant, with getType()==type |
| Opnd* |
| Simplifier::foldNegOfMultiplyByConstant(Type* type, |
| Inst* mulInst) { |
| // Note: types of the 2 ops must be the same |
| assert(type->tag == mulInst->getType()); |
| |
| ConstInst* theConstInst; |
| Opnd* nonConstSrc; |
| if (ConstantFolder::isConstant(mulInst->getSrc(0))) { |
| // C * s |
| theConstInst = mulInst->getSrc(0)->getInst()->asConstInst(); |
| nonConstSrc = mulInst->getSrc(1); |
| } else { |
| // s * C |
| theConstInst = mulInst->getSrc(1)->getInst()->asConstInst(); |
| nonConstSrc = mulInst->getSrc(0); |
| } |
| // (-C) |
| Opnd* negatedConst = fold(Op_Neg, type, theConstInst, true); |
| // (-C) * s |
| return genMul(type, Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No), negatedConst, nonConstSrc)->getDst(); |
| } |
| |
| // checks for and performs a possible s1 + (-s3) -> s1 - s3 |
| // makes no assumptions about types. |
| // works with or without overflow. |
| Opnd* |
| Simplifier::simplifyAddWithNeg(Modifier modifier, |
| Type* type, |
| Opnd* src1, |
| Opnd* src2) { |
| // |
| // s1 + (s2 = neg s3) -> s1 - s3 |
| // |
| Inst *inst2 = src2->getInst(); |
| if (isNeg(inst2) && (inst2->getType() == type->tag)) { |
| return genSub(type, modifier, src1, inst2->getSrc(0))->getDst(); |
| } |
| return NULL; |
| } |
| |
| // checks for and performs a possible s1 - (-s3) -> s1 + s3 |
| // makes no assumptions about types |
| Opnd* |
| Simplifier::simplifySubWithNeg(Modifier modifier, |
| Type* type, |
| Opnd* src1, |
| Opnd* src2) { |
| // |
| // s1 - (s2 = neg s3) -> s1 + s3 |
| // |
| Inst *inst2 = src2->getInst(); |
| if (isNeg(src2) && (inst2->getType() == type->tag)) { |
| return genAdd(type, modifier, src1, inst2->getSrc(0))->getDst(); |
| } |
| // |
| // (s1 = neg s3) - s2 -> neg (s3 + s2) |
| // |
| Inst *inst1 = src1->getInst(); |
| if (isNeg(src1) && (inst1->getType() == type->tag)) { |
| Opnd* addOpnd = |
| genAdd(type, modifier, inst1->getSrc(0), src2)->getDst(); |
| return genNeg(type, addOpnd)->getDst(); |
| } |
| return NULL; |
| } |
| |
| // checks for and performs possible re-associations of sub |
| // makes no assumptions about types |
| // assumes no overflow, no exceptions, no strict |
| Opnd* |
| Simplifier::simplifySubViaReassociation(Type* type, Opnd* src1, Opnd* src2) { |
| if (ConstantFolder::isConstant(src2)) { |
| ConstInst* constInst2 = src2->getInst()->asConstInst(); // c2 |
| ConstInst::ConstValue value = constInst2->getValue(); // c2 value |
| Inst *srcInst1 = src1->getInst(); |
| if (srcInst1->getType() != type->tag) |
| return NULL; // don't bother if types differ |
| if (isSubWithConstant(srcInst1)) { |
| // (C1 - s1) - C2 -> (C1 - C2) - s1 |
| // (s1 - C1) - C2 -> s1 + (-(C1 + C2)) |
| ConstInst* constInst1; |
| Opnd* nonConstSrc; |
| if (ConstantFolder::isConstant(srcInst1->getSrc(0))) { |
| // (C1 - s1) - C2 |
| constInst1 = srcInst1->getSrc(0)->getInst()->asConstInst(); |
| nonConstSrc = srcInst1->getSrc(1); |
| // C1-C2 |
| Opnd* constSrc = fold(Op_Sub, type, constInst1, constInst2, true); |
| // (C1-C2) - s1 |
| return genSub(type, Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No), |
| constSrc, nonConstSrc)->getDst(); |
| } else { |
| // (s1 - C1) - C2 |
| nonConstSrc = srcInst1->getSrc(0); |
| constInst1 = srcInst1->getSrc(1)->getInst()->asConstInst(); |
| // C1 + C2 |
| Opnd* constSrc = fold(Op_Add, type, constInst2, constInst1, true); |
| // -(C1+C2) |
| Opnd* constSrcNeg = fold(Op_Neg, type, |
| constSrc->getInst()->asConstInst(), true); |
| // s1 + (-(C1+C2)) |
| return genAdd(type, Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No), |
| nonConstSrc, constSrcNeg)->getDst(); |
| } |
| } |
| if (isAddWithConstant(srcInst1)) { |
| // (s + C1) - C2 -> s + (C1 - C2) |
| // (C1 + s) - C2 -> s + (C1 - C2) |
| |
| ConstInst* otherConstInst; // c1 |
| Opnd* nonConstSrc; // s |
| if (ConstantFolder::isConstant(srcInst1->getSrc(0))) { |
| // c1 + s |
| otherConstInst = srcInst1->getSrc(0)->getInst()->asConstInst(); |
| nonConstSrc = srcInst1->getSrc(1); |
| } else { |
| // s + C |
| otherConstInst = srcInst1->getSrc(1)->getInst()->asConstInst(); |
| nonConstSrc = srcInst1->getSrc(0); |
| } |
| // c1-c2 |
| Opnd* constSrc = fold(Op_Sub, type, otherConstInst, constInst2, true); |
| // s + (c1+c2) |
| return genAdd(type, Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No), nonConstSrc, constSrc)->getDst(); |
| } |
| } |
| if (ConstantFolder::isConstant(src1)) { |
| // disabled to address a compiler warning of unreferenced local variable |
| Inst *srcInst1 = src1->getInst(); |
| ConstInst* constInst1 = srcInst1->asConstInst(); // c1 |
| ConstInst::ConstValue value = constInst1->getValue(); // c1 value |
| Inst* nonConstInst = src2->getInst(); |
| if (nonConstInst->getType() != type->tag) { |
| return NULL; // types differ, don't re-associate |
| } |
| if (isSubWithConstant(nonConstInst)) { |
| // C1 - (C2 - s) -> (C1-C2) + s |
| // C1 - (s - C2) -> (C1+C2) - s |
| |
| if (ConstantFolder::isConstant(nonConstInst->getSrc(0))) { |
| // (C2 - s) |
| ConstInst *constInst2 = nonConstInst->getSrc(0)->getInst()->asConstInst(); |
| Opnd *nonConstSrc = nonConstInst->getSrc(1); |
| // C1-C2 |
| Opnd* constSrc = fold(Op_Sub, type, constInst1, constInst2, true); |
| // s+(C1-C2) |
| return genAdd(type, Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No), |
| constSrc, nonConstSrc)->getDst(); |
| } else { |
| // (s - C2) |
| Opnd *nonConstSrc = nonConstInst->getSrc(0); |
| ConstInst *constInst2 = nonConstInst->getSrc(1)->getInst()->asConstInst(); |
| // C1+C2 |
| Opnd* constSrc = fold(Op_Add, type, constInst1, constInst2, true); |
| // (C1+C2)-s |
| return genSub(type, Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No), |
| constSrc, nonConstSrc)->getDst(); |
| } |
| } |
| if (isAddWithConstant(nonConstInst)) { |
| // C1 - (s + C2) -> (C1-C2) - s |
| // C1 - (C2 + s) -> (C1-C2) - s |
| |
| ConstInst *constInst2; |
| Opnd *nonConstSrc; |
| |
| if (ConstantFolder::isConstant(nonConstInst->getSrc(0))) { |
| // (C2 + s) |
| constInst2 = nonConstInst->getSrc(0)->getInst()->asConstInst(); |
| nonConstSrc = nonConstInst->getSrc(1); |
| } else { |
| // (s + C2) |
| constInst2 = nonConstInst->getSrc(1)->getInst()->asConstInst(); |
| nonConstSrc = nonConstInst->getSrc(0); |
| } |
| // C1-C2 |
| Opnd* constSrc = fold(Op_Sub, type, constInst1, constInst2, true); |
| // (C1-C2) - s |
| return genSub(type, Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No), |
| constSrc, nonConstSrc)->getDst(); |
| } |
| } |
| return NULL; |
| } |
| |
| // checks for and performs possible re-associations of add |
| // makes no assumptions about types |
| Opnd* |
| Simplifier::simplifyAddViaReassociation(Type* type, Opnd* src1, Opnd* src2) { |
| if (ConstantFolder::isConstant(src1)) { |
| ConstInst* constInst = src1->getInst()->asConstInst(); |
| Inst* srcInst2 = src2->getInst(); |
| if (srcInst2->getType() != type->tag) |
| return NULL; // don't bother if types differ |
| if (isAddWithConstant(srcInst2)) { |
| // c1 + (c2 + s3) -> (c1+c2) + s3 |
| // c1 + (s2 + c3) -> (c1+c3) + s2 |
| return foldConstByAddingToAddWithConstant(type, constInst, srcInst2); |
| } |
| if (isSubWithConstant(srcInst2)) { |
| // c1 + (c2 - s3) -> (c1+c2) - s3 |
| // c1 + (s2 - c3) -> (c1-c3) + s2 |
| return foldConstByAddingToSubWithConstant(type, constInst, srcInst2); |
| } |
| } |
| return NULL; |
| } |
| |
| // pulls neg out of mul |
| // makes no assumptions about types |
| Opnd* |
| Simplifier::simplifyMulWithNeg(Type* type, |
| Opnd* src1, |
| Opnd* src2) { |
| // |
| // s1 * (s2 = neg s3) -> neg (s1 * s3) |
| // |
| if (isNeg(src2) && (src2->getInst()->getType() == type->tag)) { |
| Opnd *src3 = src2->getInst()->getSrc(0); |
| Opnd *mulRes = genMul(type, Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No), src1, src3)->getDst(); |
| return genNeg(type, mulRes)->getDst(); |
| } |
| return NULL; |
| } |
| |
| Opnd* |
| Simplifier::simplifyTauDivOfMul(Modifier mod, |
| Type* type, |
| Opnd* src1, |
| Opnd* src2, |
| Opnd* tauCheckedOpnds) { |
| // |
| // if (c1%c2==0), then |
| // (c1 * s1) / c2 -> (c1/c2) * s1 |
| // |
| return NULL; |
| |
| } |
| |
| //----------------------------------------------------------------------------- |
| // Arithmetic & logical simplifications |
| //----------------------------------------------------------------------------- |
| |
| // |
| // returns an Opnd if the add can be simplified, |
| // null if the operation cannot be simplified |
| // |
| Opnd* |
| Simplifier::simplifyAdd(Type* type, |
| Modifier modifier, |
| Opnd* src1, |
| Opnd* src2) { |
| // |
| // Algebraic identity |
| // |
| // 0 + s2 -> s2 |
| // |
| if (ConstantFolder::isConstantZero(src1)) |
| return src2; |
| // |
| // s1 + 0 -> s1 |
| // |
| if (ConstantFolder::isConstantZero(src2)) |
| return src1; |
| |
| // |
| // we do not simplify add with overflow any further |
| // |
| if (modifier.getOverflowModifier() != Overflow_None) |
| return NULL; |
| // |
| // Fold constants |
| // |
| // (s1 = ldconst c1) + (s2 = ldconst c2) -> ldconst fold(Op_Add, c1, c2) |
| // |
| if (ConstantFolder::isConstant(src1) && ConstantFolder::isConstant(src2)) |
| return fold(Op_Add, type, |
| src1->getInst()->asConstInst(), |
| src2->getInst()->asConstInst(), |
| true); |
| // |
| // don't simplify floating point further |
| // |
| switch (type->tag) { |
| case Type::Int32: case Type::Int64: |
| case Type::UInt32: case Type::UInt64: break; |
| default: |
| return NULL; |
| } |
| // |
| // Inversion |
| // |
| Opnd* opnd; |
| opnd = simplifyAddWithNeg(modifier, type, src1, src2); |
| if (opnd != NULL) |
| return opnd; |
| // |
| // Commute and try again |
| // |
| opnd = simplifyAddWithNeg(modifier, type, src2, src1); |
| if (opnd != NULL) |
| return opnd; |
| // |
| // Reassociate |
| // |
| opnd = simplifyAddViaReassociation(type, src1, src2); |
| if (opnd != NULL) |
| return opnd; |
| // |
| // Commute and try again |
| // |
| opnd = simplifyAddViaReassociation(type, src2, src1); |
| if (opnd != NULL) |
| return opnd; |
| // |
| if (theReassociate) { |
| opnd = simplifyAddViaReassociation2(type, src1, src2); |
| if (opnd != NULL) |
| return opnd; |
| } |
| // |
| return NULL; |
| } |
| |
| Opnd* |
| Simplifier::simplifySub(Type* type, Modifier modifier, |
| Opnd* src1, Opnd* src2) { |
| // |
| // Algebraic identity |
| // |
| // s1 - 0 -> s1 |
| // |
| if (ConstantFolder::isConstantZero(src2)) |
| return src1; |
| |
| // |
| // Fold constants |
| // |
| // (s1 = ldconst c1) - (s2 = ldconst c2) -> ldconst fold(Op_Sub, c1, c2) |
| // |
| if (ConstantFolder::isConstant(src1) && ConstantFolder::isConstant(src2)) |
| return fold(Op_Sub, type, |
| src1->getInst()->asConstInst(), |
| src2->getInst()->asConstInst(), |
| true); |
| |
| // |
| // don't simplify floating point further |
| // |
| switch (type->tag) { |
| case Type::Int32: case Type::Int64: |
| case Type::UInt32: case Type::UInt64: |
| break; |
| default: |
| return NULL; |
| } |
| // |
| // 0 - s2 -> neg s2 |
| // |
| if (ConstantFolder::isConstantZero(src1)) |
| return genNeg(type, src2)->getDst(); |
| |
| // x - x -> 0 |
| if (src1 == src2) { |
| ConstInst::ConstValue zeroval; |
| switch(type->tag) { |
| case Type::Int32: return genLdConstant((I_32)0)->getDst(); |
| case Type::Int64: return genLdConstant((int64)0)->getDst(); |
| default: assert(0); return NULL; |
| } |
| } |
| // |
| // we do not simplify sub with overflow any further |
| // we could do folding and check for overflow; for now we punt |
| // |
| if (modifier.getOverflowModifier() != Overflow_None) |
| return NULL; |
| |
| // |
| // Inversion |
| // |
| Opnd* opnd; |
| opnd = simplifySubWithNeg(modifier, type, src1, src2); |
| if (opnd != NULL) |
| return opnd; |
| |
| if (theReassociate) { |
| opnd = simplifySubViaReassociation2(type, src1, src2); |
| if (opnd != NULL) |
| return opnd; |
| } |
| |
| opnd = simplifySubViaReassociation(type, src1, src2); |
| if (opnd != NULL) |
| return opnd; |
| |
| |
| return NULL; |
| } |
| |
| Opnd* |
| Simplifier::simplifyNeg(Type* type, Opnd* src) { |
| |
| // |
| // -C |
| // |
| if (ConstantFolder::isConstant(src)) { |
| ConstInst* constInst = src->getInst()->asConstInst(); |
| return fold(Op_Neg, type, constInst, true); |
| } |
| |
| // |
| // double negation |
| // |
| if (isNeg(src)) |
| return src->getInst()->getSrc(0); |
| |
| // |
| // don't simplify floating point further |
| // |
| switch (type->tag) { |
| case Type::Int32: case Type::Int64: |
| case Type::UInt32: case Type::UInt64: |
| break; |
| default: |
| return NULL; |
| } |
| |
| if (theReassociate) { |
| Opnd *opnd = simplifyNegViaReassociation2(type, src); |
| if (opnd != NULL) |
| return opnd; |
| } |
| |
| return NULL; |
| } |
| |
| Opnd* |
| Simplifier::simplifyAnd(Type* theType, Opnd* src1, Opnd* src2) { |
| // |
| // Algebraic identity |
| // |
| // x & x -> x |
| // |
| if (src1 == src2) |
| return src1; |
| // |
| // 0 & s2 -> 0 |
| // |
| if (ConstantFolder::isConstantZero(src1)) |
| return src1; |
| // |
| // s2 & 0 -> 0 |
| // |
| if (ConstantFolder::isConstantZero(src2)) |
| return src2; |
| // |
| // 0xf..f & s2 -> s2 |
| // |
| if (ConstantFolder::isConstantAllOnes(src1)) |
| return src2; |
| // |
| // s1 & 0xf..f -> s1 |
| // |
| if (ConstantFolder::isConstantAllOnes(src2)) |
| return src1; |
| |
| // |
| // Fold constants |
| // |
| if (ConstantFolder::isConstant(src1) && ConstantFolder::isConstant(src2)) |
| return fold(Op_And, theType, |
| src1->getInst()->asConstInst(), |
| src2->getInst()->asConstInst(), |
| true); |
| |
| const OptimizerFlags& optimizerFlags = irManager.getOptimizerFlags(); |
| // check for And of 0xff with zxt/sxt:i1, etc. |
| if (optimizerFlags.do_sxt && |
| (ConstantFolder::isConstant(src1) || ConstantFolder::isConstant(src2))) { |
| Inst *inst2 = src2->getInst(); |
| Type::Tag typeTag2 = inst2->getType(); |
| Inst *inst1 = src1->getInst(); |
| Type::Tag typeTag1 = inst1->getType(); |
| int64 val64; |
| I_32 val32; |
| if (ConstantFolder::isConstant(src1->getInst(), val64) && |
| (inst2->getOpcode() == Op_Conv) && |
| (((typeTag2 == Type::Int8) && (((uint64)val64) <= 0xff)) || |
| ((typeTag2 == Type::Int16) && (((uint64)val64) <= 0xffff)) || |
| ((typeTag2 == Type::Int32) && (((uint64)val64) <= 0xffffffff)))) { |
| Opnd *src2opnd = inst2->getSrc(0); |
| if (src2opnd->getType() == src2->getType()) { |
| return genAnd(theType, src1, src2opnd)->getDst(); |
| } |
| } else if (ConstantFolder::isConstant(src2->getInst(), val64) && |
| (inst1->getOpcode() == Op_Conv) && |
| (((typeTag1 == Type::Int8) && (((uint64)val64) <= 0xff)) || |
| ((typeTag1 == Type::Int16) && (((uint64)val64) <= 0xffff)) || |
| ((typeTag1 == Type::Int32) && (((uint64)val64) <= 0xffffffff)))) { |
| Opnd *src1opnd = inst1->getSrc(0); |
| if (src1opnd->getType() == src1->getType()) { |
| return genAnd(theType, src1opnd, src2)->getDst(); |
| } |
| } else if (ConstantFolder::isConstant(src1->getInst(), val32) && |
| (inst2->getOpcode() == Op_Conv) && |
| (((typeTag2 == Type::Int8) && (((U_32)val32) <= 0xff)) || |
| ((typeTag2 == Type::Int16) && (((U_32)val32) <= 0xffff)) || |
| ((typeTag2 == Type::Int32) && (((U_32)val32) <= 0xffffffff)))) { |
| Opnd *src2opnd = inst2->getSrc(0); |
| if (src2opnd->getType() == src2->getType()) { |
| return genAnd(theType, src1, src2opnd)->getDst(); |
| } |
| } else if (ConstantFolder::isConstant(src2->getInst(), val32) && |
| (inst1->getOpcode() == Op_Conv) && |
| (((typeTag1 == Type::Int8) && (((U_32)val32) <= 0xff)) || |
| ((typeTag1 == Type::Int16) && (((U_32)val32) <= 0xffff)) || |
| ((typeTag1 == Type::Int32) && (((U_32)val32) <= 0xffffffff)))) { |
| Opnd *src1opnd = inst1->getSrc(0); |
| if (src1opnd->getType() == src1->getType()) { |
| return genAnd(theType, src1opnd, src2)->getDst(); |
| } |
| } |
| |
| // check for And of 0xff with ld.u1, etc. |
| if (ConstantFolder::isConstant(src1->getInst(), val64) && |
| (inst2->getOpcode() == Op_TauLdInd) && |
| (((typeTag2 == Type::UInt8) && (((uint64)val64) == 0xff)) || |
| ((typeTag2 == Type::UInt16) && (((uint64)val64) == 0xffff)) || |
| ((typeTag2 == Type::UInt32) && (((uint64)val64) == 0xffffffff)))) { |
| if (theType == src2->getType()) { |
| return src2; |
| } |
| } else if (ConstantFolder::isConstant(src2->getInst(), val64) && |
| (inst1->getOpcode() == Op_TauLdInd) && |
| (((typeTag1 == Type::UInt8) && (((uint64)val64) == 0xff)) || |
| ((typeTag1 == Type::UInt16) && (((uint64)val64) == 0xffff)) || |
| ((typeTag1 == Type::UInt32) && (((uint64)val64) == 0xffffffff)))) { |
| if (theType == src1->getType()) { |
| return src1; |
| } |
| } else if (ConstantFolder::isConstant(src1->getInst(), val32) && |
| (inst2->getOpcode() == Op_TauLdInd) && |
| (((typeTag2 == Type::UInt8) && (((U_32)val32) == 0xff)) || |
| ((typeTag2 == Type::UInt16) && (((U_32)val32) == 0xffff)) || |
| ((typeTag2 == Type::UInt32) && (((U_32)val32) == 0xffffffff)))) { |
| if (theType == src2->getType()) { |
| return src2; |
| } |
| } else if (ConstantFolder::isConstant(src2->getInst(), val32) && |
| (inst1->getOpcode() == Op_TauLdInd) && |
| (((typeTag1 == Type::UInt8) && (((U_32)val32) == 0xff)) || |
| ((typeTag1 == Type::UInt16) && (((U_32)val32) == 0xffff)) || |
| ((typeTag1 == Type::UInt32) && (((U_32)val32) == 0xffffffff)))) { |
| if (theType == src1->getType()) { |
| return src1; |
| } |
| } |
| } |
| return NULL; |
| } |
| |
| Opnd* |
| Simplifier::simplifyOr(Type* theType, Opnd* src1, Opnd* src2) { |
| // |
| // Algebraic identity |
| // |
| // x || x -> x |
| // |
| if (src1 == src2) |
| return src1; |
| // |
| // 0 | s2 -> s2 |
| // |
| if (ConstantFolder::isConstantZero(src1)) |
| return src2; |
| // |
| // s1 | 0 -> s1 |
| // |
| if (ConstantFolder::isConstantZero(src2)) |
| return src1; |
| // |
| // 0xf..f | s2 -> 0xf..f |
| // |
| if (ConstantFolder::isConstantAllOnes(src1)) |
| return src1; |
| // |
| // s1 | 0xf..f -> 0xf..f |
| // |
| if (ConstantFolder::isConstantAllOnes(src2)) |
| return src2; |
| |
| // |
| // Fold constants |
| // |
| if (ConstantFolder::isConstant(src1) && ConstantFolder::isConstant(src2)) |
| return fold(Op_Or, theType, |
| src1->getInst()->asConstInst(), |
| src2->getInst()->asConstInst(), |
| true); |
| return NULL; |
| } |
| |
| Opnd* |
| Simplifier::simplifyXor(Type* theType, Opnd* src1, Opnd* src2) { |
| // |
| // Algebraic identity |
| // |
| // 0 ^ s2 -> s2 |
| // |
| if (ConstantFolder::isConstantZero(src1)) |
| return src2; |
| // |
| // s1 ^ 0 -> s1 |
| // |
| if (ConstantFolder::isConstantZero(src2)) |
| return src1; |
| // |
| // 0xf..f ^ s2 -> not(s2) |
| // |
| if (ConstantFolder::isConstantAllOnes(src1)) |
| return simplifyNot(theType, src2); |
| // |
| // s1 ^ 0xf..f -> not(s1) |
| // |
| if (ConstantFolder::isConstantAllOnes(src2)) |
| return simplifyNot(theType, src1); |
| |
| // |
| // Fold constants |
| // |
| if (ConstantFolder::isConstant(src1) && ConstantFolder::isConstant(src2)) |
| return fold(Op_Xor, theType, |
| src1->getInst()->asConstInst(), |
| src2->getInst()->asConstInst(), |
| true); |
| return NULL; |
| } |
| |
| Opnd* |
| Simplifier::simplifyNot(Type* theType, Opnd* src1) { |
| // |
| // Fold constants |
| // |
| if (ConstantFolder::isConstant(src1)) |
| return fold(Op_Not, theType, |
| src1->getInst()->asConstInst(), |
| true); |
| return NULL; |
| } |
| |
| Opnd* |
| Simplifier::simplifyMulViaReassociation(Type* type, Opnd* src1, Opnd* src2) { |
| if (ConstantFolder::isConstant(src1)) { |
| ConstInst* constInst = src1->getInst()->asConstInst(); |
| Inst* srcInst2 = src2->getInst(); |
| if (isAddWithConstant(srcInst2)) { |
| // |
| // c1 * (c2 + s3) -> (c1*c2) + c1*s3 |
| // c1 * (s2 + c3) -> (c1*c3) + c1*s2 |
| // |
| return foldConstMultiplyByAddWithConstant(type, constInst, srcInst2); |
| } |
| if (isMultiplyByConstant(srcInst2)) { |
| // |
| // c1 * (c2 * s3) -> (c1*c2) * s3 |
| // c1 * (s2 * c3) -> (c1*c3) * s2 |
| // |
| return foldConstMultiplyByMulWithConstant(type, constInst, srcInst2); |
| } |
| if (isSubWithConstant(srcInst2)) { |
| // |
| // c1 * (c2 - s3) -> (c1*c2) - c1*s3 |
| // c1 * (s2 - c3) -> (c1*(-c3)) + c1*s2 |
| // |
| return foldConstMultiplyBySubWithConstant(type, constInst, srcInst2); |
| } |
| } |
| return NULL; |
| } |
| |
| |
| Opnd* |
| Simplifier::simplifyMul(Type* type, |
| Modifier modifier, |
| Opnd* src1, |
| Opnd* src2) { |
| |
| |
| bool src1isConstant = ConstantFolder::isConstant(src1); |
| bool src2isConstant = ConstantFolder::isConstant(src2); |
| // |
| // Algebraic identity |
| // |
| // 1 * s2 -> s2 |
| // |
| if (src1isConstant && ConstantFolder::isConstantOne(src1)) |
| return src2; |
| // |
| // s1 * 1 -> s1 |
| // |
| if (src2isConstant && ConstantFolder::isConstantOne(src2)) |
| return src1; |
| |
| if (!type->isFP()) { |
| |
| // |
| // Fold to 0 |
| // |
| // 0 * s2 -> 0 |
| // |
| if (src1isConstant && ConstantFolder::isConstantZero(src1)) |
| return src1; |
| // |
| // s1 * 0 -> 0 |
| // |
| if (src2isConstant && ConstantFolder::isConstantZero(src2)) |
| return src2; |
| } |
| |
| // |
| // we do not simplify mul with overflow any further |
| // we could do folding and check for overflow; for now we punt |
| // |
| if (modifier.getOverflowModifier() != Overflow_None) |
| return NULL; |
| |
| // |
| // Fold constants |
| // |
| // (s1 = ldconst c1) * (s2 = ldconst c2) -> ldconst fold(Op_Mul, c1, c2) |
| // |
| if (src1isConstant && src2isConstant) |
| return fold(Op_Mul, type, |
| src1->getInst()->asConstInst(), |
| src2->getInst()->asConstInst(), |
| true); |
| |
| // |
| // limit the types we consider further |
| // |
| switch (type->tag) { |
| case Type::Int32: case Type::Int64: break; |
| case Type::UInt32: case Type::UInt64: break; |
| default: |
| return NULL; |
| } |
| |
| // reduce multiply-by-constant |
| if (src1isConstant || src2isConstant) { |
| switch (type->tag) { |
| case Type::Int32: |
| case Type::UInt32: |
| if (src1isConstant) { |
| I_32 multiplier; |
| bool t = ConstantFolder::isConstant(src1->getInst(), |
| multiplier); |
| if( !t) assert(0); |
| Opnd *product = planMul32(multiplier, src2); |
| return product; |
| } else { // src2isConstant |
| I_32 multiplier; |
| bool t = ConstantFolder::isConstant(src2->getInst(), |
| multiplier); |
| if( !t) assert(0); |
| Opnd *product = planMul32(multiplier, src1); |
| return product; |
| } |
| |
| case Type::Int64: |
| case Type::UInt64: |
| if (src1isConstant) { |
| int64 multiplier; |
| bool t = ConstantFolder::isConstant(src1->getInst(), |
| multiplier); |
| if( !t) assert(0); |
| Opnd *product = planMul64(multiplier, src2); |
| return product; |
| } else { // src2isConstant |
| int64 multiplier; |
| bool t = ConstantFolder::isConstant(src2->getInst(), |
| multiplier); |
| if( !t) assert(0); |
| Opnd *product = planMul64(multiplier, src1); |
| return product; |
| } |
| |
| default: |
| break; |
| } |
| } |
| |
| |
| // |
| // Inversion |
| // |
| |
| // a * (- b) -> - (a * b) |
| Opnd* opnd; |
| opnd = simplifyMulWithNeg(type, src1, src2); |
| if (opnd != NULL) |
| return opnd; |
| |
| // |
| // Reassociate |
| // |
| opnd = simplifyMulViaReassociation(type, src1, src2); |
| if (opnd != NULL) |
| return opnd; |
| // |
| // Commute and try again |
| // |
| opnd = simplifyMulViaReassociation(type, src2, src1); |
| if (opnd != NULL) |
| return opnd; |
| // |
| if (theReassociate) { |
| opnd = simplifyMulViaReassociation2(type, src1, src2); |
| if (opnd != NULL) |
| return opnd; |
| } |
| // |
| return NULL; |
| } |
| |
| Opnd* |
| Simplifier::simplifyMulHi(Type* type, |
| Modifier modifier, |
| Opnd* src1, |
| Opnd* src2) { |
| |
| // |
| // Fold constants |
| // |
| // (s1 = ldconst c1) * (s2 = ldconst c2) -> ldconst fold(Op_Mul, c1, c2) |
| // |
| bool src1isConstant = ConstantFolder::isConstant(src1); |
| bool src2isConstant = ConstantFolder::isConstant(src2); |
| if (src1isConstant && src2isConstant) |
| return fold(Op_MulHi, type, |
| src1->getInst()->asConstInst(), |
| src2->getInst()->asConstInst(), |
| Type::isSignedInteger(type->tag)); |
| |
| // |
| // Algebraic identity |
| // |
| // 1 * s2 -> s2 |
| // |
| if ((src1isConstant && ConstantFolder::isConstantOne(src1)) || |
| (src2isConstant && ConstantFolder::isConstantOne(src2))) { |
| if (modifier.isSigned()) { |
| return NULL; |
| } else { |
| switch (type->tag) { |
| case Type::Int32: |
| case Type::UInt32: |
| return genLdConstant((I_32) 0)->getDst(); |
| case Type::Int64: |
| case Type::UInt64: |
| return genLdConstant((int64) 0)->getDst(); |
| default: |
| break; |
| } |
| return NULL; |
| } |
| } |
| |
| assert(!type->isFP()); |
| |
| // |
| // Fold to 0 |
| // |
| // 0 * s2 -> 0 |
| // |
| if (src1isConstant && ConstantFolder::isConstantZero(src1)) |
| return src1; |
| // |
| // s1 * 0 -> 0 |
| // |
| if (src2isConstant && ConstantFolder::isConstantZero(src2)) |
| return src2; |
| |
| // reduce multiply-by-constant |
| if (src1isConstant || src2isConstant) { |
| bool isSigned = false; |
| switch (type->tag) { |
| case Type::Int32: isSigned = true; |
| case Type::UInt32: |
| if (src1isConstant) { |
| TypeManager &tm = irManager.getTypeManager(); |
| I_32 multiplier; |
| bool t = ConstantFolder::isConstant(src1->getInst(), |
| multiplier); |
| if( !t) assert(0); |
| Type *dstType64 = tm.getInt64Type(); |
| Opnd *src2_64 = genConv(dstType64, |
| (isSigned |
| ? Type::Int64 : Type::UInt64), |
| Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No), |
| src2)->getDst(); |
| Opnd *product = planMul32(multiplier, src2_64); |
| Opnd *thirtytwo = genLdConstant((I_32)(32))->getDst(); |
| Opnd *shifted = genShr(dstType64, |
| Modifier(UnsignedOp)|Modifier(ShiftMask_None), |
| product, thirtytwo)->getDst(); |
| Opnd *res = genConv(src1->getType(), Type::Int32, |
| Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No), |
| shifted)->getDst(); |
| return res; |
| } else { // src2isConstant |
| I_32 multiplier; |
| bool t = ConstantFolder::isConstant(src2->getInst(), |
| multiplier); |
| if( !t) assert(0); |
| TypeManager &tm = irManager.getTypeManager(); |
| Type *dstType64 = tm.getInt64Type(); |
| Opnd *src1_64 = genConv(dstType64, |
| (isSigned ? Type::Int64 : Type::UInt64), |
| Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No), |
| src1)->getDst(); |
| Opnd *product = planMul32(multiplier, src1_64); |
| Opnd *thirtytwo = genLdConstant((I_32)(32))->getDst(); |
| Opnd *shifted = genShr(dstType64, |
| Modifier(UnsignedOp)|Modifier(ShiftMask_None), |
| product, thirtytwo)->getDst(); |
| Opnd *res = genConv(src1->getType(), Type::Int32, |
| Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No), |
| shifted)->getDst(); |
| return res; |
| } |
| |
| default: |
| break; |
| } |
| } |
| |
| return NULL; |
| } |
| |
| Opnd* |
| Simplifier::simplifyMin(Type* dstType, |
| Opnd* src1, |
| Opnd* src2) { |
| if (ConstantFolder::isConstant(src1)) { |
| if (ConstantFolder::isConstant(src2)) { |
| return fold(Op_Min, dstType, |
| src1->getInst()->asConstInst(), |
| src2->getInst()->asConstInst(), |
| true); |
| } |
| } |
| if (src1 == src2) { |
| return src1; |
| } |
| return NULL; |
| } |
| |
| Opnd* |
| Simplifier::simplifyMax(Type* dstType, |
| Opnd* src1, |
| Opnd* src2) { |
| if (ConstantFolder::isConstant(src1)) { |
| if (ConstantFolder::isConstant(src2)) { |
| return fold(Op_Max, dstType, |
| src1->getInst()->asConstInst(), |
| src2->getInst()->asConstInst(), |
| true); |
| } |
| } |
| if (src1 == src2) { |
| return src1; |
| } |
| return NULL; |
| } |
| |
| Opnd* |
| Simplifier::simplifyAbs(Type* dstType, |
| Opnd* src1) { |
| if (ConstantFolder::isConstant(src1)) { |
| return fold(Op_Abs, dstType, |
| src1->getInst()->asConstInst(), |
| true); |
| } |
| return NULL; |
| } |
| |
| Opnd* |
| Simplifier::simplifyTauDiv(Type* dstType, |
| Modifier mod, |
| Opnd* src1, |
| Opnd* src2, |
| Opnd* tauOpndsChecked) { |
| // |
| // constant-fold anything; check for 0 occurs inside fold() |
| // if (c2 != 0) |
| // (s1 = ldconst c1) / (s2 = ldconst c2) -> ldconst fold(Op_Mul, c1, c2) |
| // |
| if (ConstantFolder::isConstant(src1) && |
| ConstantFolder::isConstant(src2)) |
| return fold(Op_TauDiv, dstType, |
| src1->getInst()->asConstInst(), |
| src2->getInst()->asConstInst(), |
| mod.isSigned()); |
| |
| |
| const OptimizerFlags& optimizerFlags = irManager.getOptimizerFlags(); |
| // |
| // further ops only for integers |
| // |
| switch (dstType->tag) { |
| case Type::Int32: case Type::Int64: break; |
| default: |
| return NULL; |
| } |
| // Algebraic identity |
| |
| // |
| // Div by constant might simplify |
| // |
| ConstInst::ConstValue value2; |
| if (ConstantFolder::isConstant(src2->getInst(), value2)) { |
| // |
| // s1 / 1 -> s1 |
| // |
| if ((dstType->tag == Type::Int32) |
| ? (value2.i4 == 1) |
| : (value2.i8 == 1)) |
| return src1; |
| |
| // shouldn't happen |
| if ((dstType->tag == Type::Int32) |
| ? (value2.i4 == 0) |
| : (value2.i8 == 0)) |
| return src1; |
| |
| // |
| // if (c1%c2 == 0), then |
| // (s1 * c1) / c2 -> s1 * (c1/c2) |
| // |
| Opnd* opnd = simplifyTauDivOfMul(mod, dstType, src1, src2, tauOpndsChecked); |
| if (opnd != NULL) |
| return opnd; |
| |
| // convert other cases to MulHi and shift if lower_divconst set |
| if (optimizerFlags.lower_divconst && mod.isSigned()) { |
| if (dstType->tag == Type::Int32) { |
| I_32 denom = value2.i4; |
| // note that 0 and 1 were handled above |
| if (denom == -1) { |
| // convert to neg |
| Opnd *res = genNeg(dstType, src1)->getDst(); |
| return res; |
| } else if (isPowerOf2<I_32>(denom)) { |
| // convert to shift and such |
| I_32 absdenom = (denom < 0) ? -denom : denom; |
| int k = whichPowerOf2<I_32,32>(absdenom); |
| Opnd *kminus1 = genLdConstant((I_32)(k - 1))->getDst(); |
| // make k-1 copies of the sign bit |
| Opnd *shiftTheSign = genShr(dstType, |
| Modifier(SignedOp)|Modifier(ShiftMask_None), |
| src1, kminus1)->getDst(); |
| // we 32-k zeros in on left to put copies of sign on right |
| Opnd *t32minusk = genLdConstant((I_32)(32-k))->getDst(); |
| // if (n<0), this is 2^k-1, else 0 |
| Opnd *kminus1ones = genShr(dstType, |
| Modifier(UnsignedOp)|Modifier(ShiftMask_None), |
| shiftTheSign, t32minusk)->getDst(); |
| Opnd *added = genAdd(dstType, Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No), |
| src1, kminus1ones)->getDst(); |
| Opnd *kOpnd = genLdConstant((I_32)k)->getDst(); |
| Opnd *res = genShr(dstType, Modifier(SignedOp)|Modifier(ShiftMask_None), |
| added, kOpnd)->getDst(); |
| if (denom != absdenom) { // ((denom < 0) && (k < 31)) |
| res = genNeg(dstType, res)->getDst(); |
| } |
| return res; |
| } else { |
| // convert to MulHi and such |
| I_32 magicNum, shiftBy; |
| getMagic<I_32, U_32, 32>(denom, &magicNum, &shiftBy); |
| |
| Opnd *mulRes; |
| if (optimizerFlags.use_mulhi) { |
| Opnd *magicOpnd = genLdConstant(magicNum)->getDst(); |
| mulRes = genMulHi(dstType, SignedOp, magicOpnd, |
| src1)->getDst(); |
| } else { |
| Opnd *magicOpnd = genLdConstant((int64)magicNum)->getDst(); |
| TypeManager &tm = irManager.getTypeManager(); |
| Type *dstType64 = tm.getInt64Type(); |
| Opnd *src64 = genConv(dstType64, Type::Int64, Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No), |
| src1)->getDst(); |
| Opnd *mulRes64 = genMul(dstType64, Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No), magicOpnd, |
| src64)->getDst(); |
| Opnd *constant32 = genLdConstant((I_32)32)->getDst(); |
| Opnd *mulRes64h = genShr(dstType64, |
| Modifier(SignedOp)|Modifier(ShiftMask_None), |
| mulRes64, |
| constant32)->getDst(); |
| mulRes = genConv(dstType, Type::Int32, Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No), |
| mulRes64h)->getDst(); |
| } |
| // need to adjust for overflow in magicNum |
| // this is indicated by sign which differs from |
| // the denom. |
| if ((denom > 0) && (magicNum < 0)) { |
| mulRes = genAdd(dstType, Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No), |
| mulRes, src1)->getDst(); |
| } else if ((denom < 0) && (magicNum > 0)) { |
| mulRes = genSub(dstType, Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No), |
| mulRes, src1)->getDst(); |
| } |
| Opnd *shiftByOpnd = genLdConstant(shiftBy)->getDst(); |
| mulRes = genShr(dstType, Modifier(SignedOp)|Modifier(ShiftMask_None), |
| mulRes, shiftByOpnd)->getDst(); |
| Opnd *thirtyOne = genLdConstant((I_32)31)->getDst(); |
| Opnd *oneIfNegative = genShr(dstType, |
| Modifier(UnsignedOp)|Modifier(ShiftMask_None), |
| ((denom < 0) |
| ? mulRes |
| : src1), |
| thirtyOne)->getDst(); |
| Opnd *res = genAdd(dstType, Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No), mulRes, oneIfNegative)->getDst(); |
| return res; |
| } |
| } else if (dstType->tag == Type::Int64) { |
| int64 denom = value2.i8; |
| // note that 0 and 1 were handled above |
| if (denom == -1) { |
| // convert to neg |
| Opnd *res = genNeg(dstType, src1)->getDst(); |
| return res; |
| } else if (isPowerOf2<int64>(denom)) { |
| // convert to shift and such |
| int64 absdenom = (denom < 0) ? -denom : denom; |
| int k = whichPowerOf2<int64,64>(absdenom); |
| Opnd *kminus1 = genLdConstant((int64)(k - 1))->getDst(); |
| // make k-1 copies of the sign bit |
| Opnd *shiftTheSign = genShr(dstType, |
| Modifier(SignedOp)|Modifier(ShiftMask_None), |
| src1, kminus1)->getDst(); |
| // we 64-k zeros in on left to put copies of sign on right |
| Opnd *t64minusk = genLdConstant((int64)(64-k))->getDst(); |
| // if (n<0), this is 2^k-1, else 0 |
| Opnd *kminus1ones = genShr(dstType, |
| Modifier(UnsignedOp)|Modifier(ShiftMask_None), |
| shiftTheSign, t64minusk)->getDst(); |
| Opnd *added = genAdd(dstType, Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No), |
| src1, kminus1ones)->getDst(); |
| Opnd *kOpnd = genLdConstant((int64)k)->getDst(); |
| Opnd *res = genShr(dstType, Modifier(SignedOp)|Modifier(ShiftMask_None), |
| added, kOpnd)->getDst(); |
| if (denom != absdenom) { // ((denom < 0) && (k < 63)) |
| res = genNeg(dstType, res)->getDst(); |
| } |
| return res; |
| } |
| } |
| } |
| } |
| |
| return NULL; |
| } |
| |
| Opnd* |
| Simplifier::simplifyTauRem(Type* dstType, |
| Modifier mod, |
| Opnd* src1, |
| Opnd* src2, |
| Opnd* tauOpndsChecked) { |
| // |
| // Fold constants |
| // |
| // if (c2 != 0) |
| // (s1 = ldconst c1) / (s2 = ldconst c2) -> ldconst fold(Op_Rem, c1, c2) |
| // |
| // check for 0 occurs inside fold() |
| if (ConstantFolder::isConstant(src1) && |
| ConstantFolder::isConstant(src2)) |
| return fold(Op_TauRem, dstType, |
| src1->getInst()->asConstInst(), |
| src2->getInst()->asConstInst(), |
| mod.isSigned()); |
| |
| // |
| // don't simplify floating point further |
| // |
| switch (dstType->tag) { |
| case Type::Int32: case Type::Int64: break; |
| case Type::UInt32: case Type::UInt64: break; |
| default: |
| return NULL; |
| } |
| |
| // Algebraic identity |
| |
| // |
| // Rem by constant might simplify |
| // |
| if (ConstantFolder::isConstant(src2)) { |
| if (ConstantFolder::isConstantOne(src2)) { |
| ConstInst::ConstValue zeroval; |
| switch(dstType->tag) { |
| case Type::Int32: return genLdConstant((I_32)0)->getDst(); |
| case Type::Int64: return genLdConstant((int64)0)->getDst(); |
| default: assert(0); return NULL; |
| } |
| } |
| |
| if (ConstantFolder::isConstantZero(src2)) |
| return NULL; |
| |
| // convert rem by powers of 2 into bitwise "and" operations |
| // also handle 1 and -1 here. |
| Inst *src2inst = src2->getInst(); |
| ConstInst::ConstValue cv; |
| if (ConstantFolder::isConstant(src2inst, cv.i4)) { |
| I_32 denom = cv.i4; |
| if ((denom == -1) || (denom == 1)) { |
| // |
| // s1 % +-1 -> 0 |
| // |
| return genLdConstant((I_32)0)->getDst(); |
| } |
| } else if (ConstantFolder::isConstant(src2inst, cv.i8)) { |
| int64 denom = cv.i8; |
| if ((denom == -1) || (denom == 1)) { |
| // |
| // s1 % +-1 -> 0 |
| // |
| return genLdConstant((int64)0)->getDst(); |
| } |
| } |
| |
| // convert other cases to MulHi and shift, and Mul |
| // just use div |
| Opnd *tryDiv = simplifyTauDiv(dstType, mod, src1, src2, tauOpndsChecked); |
| if (tryDiv) { |
| // div worked, use it |
| Opnd *divProduct = genMul(dstType, Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No), |
| tryDiv, src2)->getDst(); |
| Opnd *remOpnd = genSub(dstType, Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No), |
| src1, divProduct)->getDst(); |
| return remOpnd; |
| } |
| } |
| |
| return NULL; |
| } |
| //----------------------------------------------------------------------------- |
| // Conversion, shift and comparison simplifications |
| //----------------------------------------------------------------------------- |
| Opnd* |
| Simplifier::simplifyConv(Type* dstType, |
| Type::Tag toType, |
| Modifier ovfmod, |
| Opnd* src) { |
| // get rid of redundant conversion |
| Inst *opndInst = src->getInst(); |
| if (toType == opndInst->getType() && (dstType == src->getType())) { |
| return src; |
| } |
| ConstInst *cinst = opndInst->asConstInst(); |
| if (cinst) { |
| ConstInst::ConstValue srcval = cinst->getValue(); |
| ConstInst::ConstValue res; |
| Type::Tag fromType = opndInst->getType(); |
| if (ConstantFolder::foldConv(fromType, toType, ovfmod, srcval, res)) { |
| if (dstType->tag == toType) |
| return genLdConstant(dstType, res)->getDst(); |
| } |
| } |
| const OptimizerFlags& optimizerFlags = irManager.getOptimizerFlags(); |
| if (optimizerFlags.do_sxt && (opndInst->getOpcode() == Op_And)) { |
| assert(opndInst->getNumSrcOperands() == 2); |
| Opnd *src0 = opndInst->getSrc(0); |
| Opnd *src1 = opndInst->getSrc(1); |
| int64 val64; |
| // and with 0xff makes Conv(u8) redundant, etc.. |
| if (ConstantFolder::isConstant(src0->getInst(), val64) && |
| (((toType == Type::UInt8) |
| && (((uint64)val64) <= 0xff)) || |
| ((toType == Type::Int8) |
| && (((uint64)val64) <= 0x7f)) || |
| ((toType == Type::UInt16) |
| && (((uint64)val64) <= 0x7fff)) || |
| ((toType == Type::Int16) |
| && (((uint64)val64) <= 0xffff)) || |
| ((toType == Type::UInt32) |
| && (((uint64)val64) <= 0xffffffff)) || |
| ((toType == Type::Int32) |
| && (((uint64)val64) <= 0x7fffffff)))) { |
| if (dstType == src->getType()) |
| return src; |
| } else if (ConstantFolder::isConstant(src1->getInst(), val64) && |
| (((toType == Type::UInt8) |
| && (((uint64)val64) <= 0xff)) || |
| ((toType == Type::Int8) |
| && (((uint64)val64) <= 0x7f)) || |
| ((toType == Type::UInt16) |
| && (((uint64)val64) <= 0xffff)) || |
| ((toType == Type::Int16) |
| && (((uint64)val64) <= 0x7fff)) || |
| ((toType == Type::UInt32) |
| && (((uint64)val64) <= 0xffffffff)) || |
| ((toType == Type::Int32) |
| && (((uint64)val64) <= 0x7fffffff)))) { |
| if (dstType == src->getType()) |
| return src; |
| } |
| I_32 val32; |
| if (ConstantFolder::isConstant(src0->getInst(), val32) && |
| (((toType == Type::UInt8) |
| && (((U_32)val32) <= 0xff)) || |
| ((toType == Type::Int8) |
| && (((U_32)val32) <= 0x7f)) || |
| ((toType == Type::UInt16) |
| && (((U_32)val32) <= 0xffff)) || |
| ((toType == Type::Int16) |
| && (((U_32)val32) <= 0x7fff)) || |
| ((toType == Type::UInt32) |
| && (((U_32)val32) <= 0xffffffff)) || |
| ((toType == Type::Int32) |
| && (((U_32)val32) <= 0x7fffffff)))) { |
| if (dstType == src->getType()) |
| return src; |
| } else if (ConstantFolder::isConstant(src1->getInst(), val32) && |
| (((toType == Type::UInt8) |
| && (((U_32)val32) <= 0xff)) || |
| ((toType == Type::Int8) |
| && (((U_32)val32) <= 0x7f)) || |
| ((toType == Type::UInt16) |
| && (((U_32)val32) <= 0xffff)) || |
| ((toType == Type::Int16) |
| && (((U_32)val32) <= 0x7fff)) || |
| ((toType == Type::UInt32) |
| && (((U_32)val32) <= 0xffffffff)) || |
| ((toType == Type::Int32) |
| && (((U_32)val32) <= 0x7fffffff)))) { |
| if (dstType == src->getType()) |
| return src; |
| } |
| } |
| |
| |
| |
| return NULL; |
| } |
| |
| Opnd* |
| Simplifier::simplifyConvZE(Type* dstType, |
| Type::Tag toType, |
| Modifier ovfmod, |
| Opnd* src) |
| { |
| // get rid of redundant conversion |
| Inst *opndInst = src->getInst(); |
| if (toType == opndInst->getType() && (dstType == src->getType())) { |
| return src; |
| } |
| ConstInst *cinst = opndInst->asConstInst(); |
| if (cinst) { |
| ConstInst::ConstValue srcval = cinst->getValue(); |
| ConstInst::ConstValue res; |
| Type::Tag fromType = opndInst->getType(); |
| if (ConstantFolder::foldConv(fromType, toType, ovfmod, srcval, res)) { |
| if (dstType->tag == toType) |
| return genLdConstant(dstType, res)->getDst(); |
| } |
| } |
| return NULL; |
| } |
| |
| Opnd* |
| Simplifier::simplifyConvUnmanaged(Type* dstType, |
| Type::Tag toType, |
| Modifier ovfmod, |
| Opnd* src) |
| { |
| // get rid of redundant conversion |
| Inst *opndInst = src->getInst(); |
| if (toType == opndInst->getType() && (dstType == src->getType())) { |
| return src; |
| } |
| ConstInst *cinst = opndInst->asConstInst(); |
| if (cinst) { |
| ConstInst::ConstValue srcval = cinst->getValue(); |
| ConstInst::ConstValue res; |
| Type::Tag fromType = opndInst->getType(); |
| if (ConstantFolder::foldConv(fromType, toType, ovfmod, srcval, res)) { |
| if (dstType->tag == toType) |
| return genLdConstant(dstType, res)->getDst(); |
| } |
| } |
| return NULL; |
| } |
| |
| |
| Opnd* |
| Simplifier::simplifyShladd(Type* dstType, |
| Opnd* value, |
| Opnd* shiftAmount, |
| Opnd* addto) { |
| |
| if (ConstantFolder::isConstantZero(shiftAmount)) |
| return genAdd(dstType, Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No), value, addto)->getDst(); |
| |
| return NULL; |
| } |
| |
| Opnd* |
| Simplifier::simplifyShl(Type* dstType, |
| Modifier mod, |
| Opnd* value, |
| Opnd* shiftAmount) { |
| |
| if (ConstantFolder::isConstantZero(shiftAmount)) |
| return value; |
| |
| return NULL; |
| } |
| |
| Opnd* |
| Simplifier::simplifyShr(Type* dstType, |
| Modifier mod1, |
| Opnd* value, |
| Opnd* shiftAmount) { |
| if (ConstantFolder::isConstantZero(shiftAmount)) |
| return value; |
| |
| return NULL; |
| } |
| |
| Opnd* |
| Simplifier::simplifySelect(Type* dstType, |
| Opnd* src1, |
| Opnd* src2, |
| Opnd* src3) { |
| if (ConstantFolder::isConstant(src1)) { |
| if (ConstantFolder::isConstantZero(src1)) { |
| return src3; |
| } else { |
| return src2; |
| } |
| } |
| if (src2 == src3) { |
| return src2; |
| } |
| if (src1->getInst()->getOpcode() == Op_Cmp) { |
| if (ConstantFolder::isConstantOne(src2) && |
| ConstantFolder::isConstantZero(src3)) { |
| return src1; |
| } |
| } |
| return NULL; |
| } |
| |
| Opnd* |
| Simplifier::simplifyCmp(Type* dstType, |
| Type::Tag instType, // source type |
| ComparisonModifier mod, |
| Opnd* src1, |
| Opnd* src2) { |
| ConstInst::ConstValue res; |
| if (ConstantFolder::isConstant(src1)) { |
| if (ConstantFolder::isConstant(src2)) { |
| return foldComparison(mod, |
| instType, |
| src1->getInst()->asConstInst(), |
| src2->getInst()->asConstInst()); |
| } else { |
| // can fold if (src1 == 0) and comparison is Cmp_Gt_Un |
| if (ConstantFolder::isConstantZero(src1) && |
| ((mod & Cmp_Mask)==Cmp_GT_Un)) { |
| switch (dstType->tag) { |
| case Type::Int32: return genLdConstant((I_32)0)->getDst(); |
| default: |
| break; |
| } |
| } |
| } |
| } else if (ConstantFolder::isConstantZero(src2) && |
| ((mod & Cmp_Mask) == Cmp_GTE_Un)) { |
| switch (dstType->tag) { |
| case Type::Int32: return genLdConstant((I_32)1)->getDst(); |
| default: |
| break; |
| } |
| } |
| // if operands are identical and not FP, then we can simplify it now |
| if ((src1 == src2) && !Type::isFloatingPoint(instType)) { |
| switch (mod & Cmp_Mask) { |
| case Cmp_EQ: case Cmp_GTE: case Cmp_GTE_Un: |
| return genLdConstant((I_32)1)->getDst(); |
| case Cmp_NE_Un: case Cmp_GT: case Cmp_GT_Un: |
| return genLdConstant((I_32)0)->getDst(); |
| default: |
| assert(0); |
| } |
| } |
| |
| // try to simplify to a new comparison |
| { |
| ComparisonModifier newMod; |
| Type::Tag newInstType; |
| Opnd *newSrc1; |
| Opnd *newSrc2; |
| if (simplifyCmpToCmp(instType, mod, src1, src2, |
| newInstType, newMod, newSrc1, newSrc2)) { |
| // can simplify it. |
| Inst *res = genCmp(dstType, newInstType, newMod, |
| newSrc1, (newSrc2 |
| ? newSrc2 |
| : OpndManager::getNullOpnd())); |
| return res->getDst(); |
| } |
| } |
| return NULL; |
| } |
| |
| Opnd* |
| Simplifier::simplifyCmp3(Type* dstType, |
| Type::Tag instType, |
| ComparisonModifier mod, |
| Opnd* src1, |
| Opnd* src2) { |
| |
| ConstInst::ConstValue res; |
| if (ConstantFolder::isConstant(src1)) { |
| if (ConstantFolder::isConstant(src2)) { |
| ConstInst *srcInst1 = src1->getInst()->asConstInst(); |
| ConstInst *srcInst2 = src2->getInst()->asConstInst(); |
| ConstInst::ConstValue res; |
| if (ConstantFolder::foldCmp(instType, mod, |
| srcInst1->getValue(), |
| srcInst2->getValue(), res)) { |
| if (res.i4) { |
| return genLdConstant((I_32)1)->getDst(); |
| } else { |
| ComparisonModifier mod2 = mod; |
| if (Type::isFloatingPoint(instType)) { |
| switch (mod) { |
| case Cmp_GT: mod2 = Cmp_GT_Un; break; |
| case Cmp_GT_Un: mod2 = Cmp_GT; break; |
| case Cmp_GTE: mod2 = Cmp_GTE_Un; break; |
| case Cmp_GTE_Un: mod2 = Cmp_GTE; break; |
| default: break; |
| } |
| } |
| if (ConstantFolder::foldCmp(instType, mod2, |
| srcInst2->getValue(), |
| srcInst1->getValue(), res)) { |
| if ((U_32)res.i4) { |
| return genLdConstant((I_32)-1)->getDst(); |
| } else { |
| return genLdConstant((I_32)0)->getDst(); |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| // if operands are identical and not FP, then we can simplify it now |
| if ((src1 == src2) && !Type::isFloatingPoint(instType)) { |
| switch (mod & Cmp_Mask) { |
| case Cmp_EQ: case Cmp_GTE: case Cmp_GTE_Un: |
| return genLdConstant((I_32)1)->getDst(); |
| case Cmp_NE_Un: case Cmp_GT: case Cmp_GT_Un: |
| return genLdConstant((I_32)0)->getDst(); |
| default: |
| assert(0); |
| } |
| } |
| |
| return NULL; |
| } |
| //----------------------------------------------------------------------------- |
| // Branch simplifications |
| //----------------------------------------------------------------------------- |
| |
| // Returns true if the cmp3 can be simplified to a Cmp, |
| // given that it can yield a result of just 1 or 2 of {-1,0,1}; |
| // if so, fills in the new comparison's modifier, src1, and src2. |
| // Interface is indirect to allow us to use this for Branches, too. |
| bool |
| // Note that exactly 1 or 2 of the booleans can be true |
| Simplifier::simplifyCmp3ByResult(Opnd *cmp3Opnd, |
| bool canbe_1, // can be -1 |
| bool canbe0, |
| bool canbe1, |
| Type::Tag &newInstType, |
| ComparisonModifier &newmod, |
| Opnd* &newSrc1, |
| Opnd* &newSrc2) |
| { |
| Inst *cmp3Inst = cmp3Opnd->getInst(); |
| assert(cmp3Inst->getOpcode() == Op_Cmp3); |
| ComparisonModifier orgMod = cmp3Inst->getComparisonModifier(); |
| Type::Tag instType = cmp3Inst->getType(); |
| Opnd *src1 = cmp3Inst->getSrc(0); |
| Opnd *src2 = cmp3Inst->getSrc(1); |
| // simplify code below by initializing with original values: |
| newInstType = instType; |
| newmod = orgMod; |
| newSrc1 = src1; |
| newSrc2 = src2; |
| if (!canbe_1) { |
| if (!canbe0) { |
| // 0 0 1 - just the first test yields true |
| // just convert it to a Cmp2 with same parameters |
| return true; |
| } else if (!canbe1) { |
| // 0 1 0 - both tests yield false |
| switch (orgMod) { |
| case Cmp_EQ: // invert it |
| { |
| newmod = Cmp_NE_Un; return true; |
| } |
| case Cmp_GT: case Cmp_GT_Un: // must be equal. |
| // recall that Nan is caught by one of the two tests |
| { |
| newmod = Cmp_EQ; return true; |
| } |
| case Cmp_GTE: case Cmp_GTE_Un: |
| // recall that Nan is caught by one of the two tests |
| // can't happen, make it a foldable comparison |
| newmod = Cmp_NE_Un; newSrc2 = src1; return true; |
| default: |
| return false; |
| } |
| } else { |
| // 0 1 1 - just the 2nd test is false |
| switch (orgMod) { |
| case Cmp_EQ: |
| // should fold to always true; |
| newSrc2 = src1; return true; |
| case Cmp_NE_Un: |
| // can't happen, make it a foldable comparison |
| newmod = Cmp_NE_Un; newSrc2 = src1; return true; |
| case Cmp_GT: |
| newmod = Cmp_GTE; return true; |
| case Cmp_GT_Un: |
| newmod = Cmp_GTE_Un; return true; |
| case Cmp_GTE: |
| newmod = orgMod; return true; |
| case Cmp_GTE_Un: |
| newmod = orgMod; return true; |
| default: |
| return false; |
| } |
| } |
| } else { // canbe_1 |
| // 1 x x |
| if (!canbe0 && !canbe1) { |
| // 1 0 0 - just second test yields true |
| // second test succeeds |
| if (orgMod == Cmp_EQ) { // can happen only if one is NaN; leave it. |
| return false; |
| } else if (orgMod == Cmp_NE_Un) { |
| // can't happen, make it easily foldable to false |
| newSrc2 = src1; return true; |
| } else { |
| // just swap args |
| newSrc1 = src2; newSrc2 = src1; |
| if (Type::isFloatingPoint(instType)) { |
| // for floats, must also invert NaN handling: |
| switch (orgMod) { |
| case Cmp_GT: newmod = Cmp_GT_Un; break; |
| case Cmp_GT_Un: newmod = Cmp_GT; break; |
| case Cmp_GTE: newmod = Cmp_GTE_Un; break; |
| case Cmp_GTE_Un: newmod = Cmp_GTE_Un; break; |
| default: assert(0); break; |
| } |
| } |
| return true; |
| } |
| } else if (canbe1) { |
| // 1 0 1 - one of first two tests succeeds |
| switch (orgMod) { |
| case Cmp_GT: case Cmp_GT_Un: newmod = Cmp_NE_Un; return true; |
| case Cmp_GTE: case Cmp_GTE_Un: // shouldn't be possible |
| newSrc2 = src1; newmod = Cmp_NE_Un; return true; // false |
| case Cmp_NE_Un: |
| case Cmp_EQ: return true; // same test. |
| default: |
| assert(0); return false; |
| } |
| } else { |
| assert(canbe0); |
| // 1 1 0 - first test fails, second is irrelevant |
| newSrc1 = src2; |
| newSrc2 = src1; |
| switch (orgMod) { |
| case Cmp_EQ: newmod = Cmp_NE_Un; break; |
| case Cmp_NE_Un: newmod = Cmp_EQ; break; |
| case Cmp_GT: |
| newmod = ((Type::isFloatingPoint(instType)) |
| ? Cmp_GTE_Un |
| : Cmp_GTE); |
| |
| break; |
| case Cmp_GT_Un: |
| newmod = ((Type::isFloatingPoint(instType)) |
| ? Cmp_GTE |
| : Cmp_GTE_Un); |
| break; |
| case Cmp_GTE: |
| newmod = ((Type::isFloatingPoint(instType)) |
| ? Cmp_GT_Un |
| : Cmp_GT); |
| break; |
| case Cmp_GTE_Un: |
| newmod = ((Type::isFloatingPoint(instType)) |
| ? Cmp_GT |
| : Cmp_GT_Un); |
| break; |
| default: |
| assert(0); |
| } |
| return true; |
| } |
| } |
| } |
| |
| void cloneComparison(bool negateIt, |
| Opnd *orgCmp, |
| Type::Tag &newInstType, |
| ComparisonModifier &newmod, |
| Opnd* &newSrc1, |
| Opnd* &newSrc2) |
| { |
| Inst *orgInst = orgCmp->getInst(); |
| ComparisonModifier orgMod = orgInst->getComparisonModifier(); |
| Opnd *src1 = orgInst->getSrc(0); |
| Opnd *src2 = orgInst->getSrc(1); |
| if (negateIt) { |
| // negate the comparison, by swapping parameters and adjusting test |
| newInstType = orgInst->getType(); |
| newSrc1 = src2; |
| newSrc2 = src1; |
| if (Type::isFloatingPoint(newInstType)) { |
| // for floats, invert NaN handling |
| switch (orgMod) { |
| case Cmp_GT: newmod = Cmp_GTE_Un; break; |
| case Cmp_GT_Un: newmod = Cmp_GTE; break; |
| case Cmp_GTE: newmod = Cmp_GT_Un; break; |
| case Cmp_GTE_Un: newmod = Cmp_GT; break; |
| case Cmp_EQ: newmod = Cmp_NE_Un; break; |
| case Cmp_NE_Un: newmod = Cmp_EQ; break; |
| default: assert(0); break; |
| } |
| } else { |
| // for integers, don't modify signed/unsigned comparison |
| switch (orgMod) { |
| case Cmp_GT: newmod = Cmp_GTE; break; |
| case Cmp_GT_Un: newmod = Cmp_GTE_Un; break; |
| case Cmp_GTE: newmod = Cmp_GT; break; |
| case Cmp_GTE_Un: newmod = Cmp_GT_Un; break; |
| case Cmp_EQ: newmod = Cmp_NE_Un; break; |
| case Cmp_NE_Un: newmod = Cmp_EQ; break; |
| default: assert(0); break; |
| } |
| } |
| } else { |
| newInstType = orgInst->getType(); |
| newmod = orgMod; |
| newSrc1 = src1; |
| newSrc2 = src2; |
| } |
| } |
| |
| bool haveSameSignedTypes(Opnd* op1, Opnd *op2, Opnd *op3, Opnd *op4, |
| Modifier addMod, |
| ComparisonModifier cmpMod) |
| { |
| Type *type1 = op1->getType(); |
| if (!Type::isSignedInteger(type1->tag)) return false; |
| if (!addMod.isSigned()) return false; |
| if (!isComparisonModifierSigned(cmpMod)) return false; |
| return ((type1 == op2->getType()) && |
| (type1 == op3->getType())); |
| } |
| |
| // check for the cases of cmp(cmp3(a,b), const) |
| bool |
| Simplifier::simplifyCmpOfCmp3(Type::Tag instType, |
| ComparisonModifier mod, |
| Opnd* src1, |
| Opnd* src2, |
| Type::Tag &newInstType, |
| ComparisonModifier &newmod, |
| Opnd* &newSrc1, |
| Opnd* &newSrc2) |
| { |
| ConstInst::ConstValue valC; |
| if (src1->getInst()->getOpcode() == Op_Cmp3) { |
| if (ConstantFolder::isConstant(src2->getInst(), valC)) { |
| I_32 val = valC.i4; |
| if (((val == 0) && (mod == Cmp_GT)) || |
| ((val == 1) && ((mod == Cmp_GTE) || (mod == Cmp_EQ)))) { |
| // test == 1 |
| // test > 0 |
| // test >= 1 |
| return simplifyCmp3ByResult(src1, false, false, true, |
| newInstType, newmod, newSrc1, newSrc2); |
| } else if ((val == 0) && (mod == Cmp_EQ)) { |
| // test == 0 |
| return simplifyCmp3ByResult(src1, false, true, false, |
| newInstType, newmod, newSrc1, newSrc2); |
| } else if (((val == 0) && (mod == Cmp_GTE)) || |
| ((val == -1) && (mod == Cmp_GT))) { |
| // test >= 0 |
| // test > -1 |
| return simplifyCmp3ByResult(src1, false, true, true, |
| newInstType, newmod, newSrc1, newSrc2); |
| } else if (((val == -1) && (mod == Cmp_EQ)) || |
| ((mod == Cmp_GTE_Un) && |
| ((val < -1) || (val >= 2))) || |
| ((mod == Cmp_GT_Un) && |
| ((val < -2) || (val >= 1)))) { |
| // test == -1 |
| // test >=u 2..maxint |
| // test >=u minint..-1 |
| // test >u 1..maxint |
| // test >u minint..-2 |
| return simplifyCmp3ByResult(src1, true, false, false, |
| newInstType, newmod, newSrc1, newSrc2); |
| } else if ((val == 0) && ((mod == Cmp_GT_Un) || |
| (mod == Cmp_NE_Un))) { |
| // test != 0 |
| // test >u 0 |
| return simplifyCmp3ByResult(src1, true, false, true, |
| newInstType, newmod, newSrc1, newSrc2); |
| } else if ((val == 1) && (mod == Cmp_NE_Un)) { |
| return simplifyCmp3ByResult(src1, true, true, false, |
| newInstType, newmod, newSrc1, newSrc2); |
| } else if ((val == -1) && (mod == Cmp_NE_Un)) { |
| return simplifyCmp3ByResult(src1, false, true, true, |
| newInstType, newmod, newSrc1, newSrc2); |
| } |
| } |
| } else if (src2->getInst()->getOpcode() == Op_Cmp3) { |
| if (ConstantFolder::isConstant(src1->getInst(), valC)) { |
| I_32 val = valC.i4; |
| // val cmp Cmp3 |
| if ((val == 1) && (mod == Cmp_EQ)) { |
| // 1 == test |
| return simplifyCmp3ByResult(src2, false, false, true, |
| newInstType, newmod, newSrc1, newSrc2); |
| } else if (((val == 0) && (mod == Cmp_EQ)) || |
| ((val == 1) && (mod == Cmp_GT_Un))) { |
| // 0 == test |
| // 1 >u test |
| return simplifyCmp3ByResult(src2, false, true, false, |
| newInstType, newmod, newSrc1, newSrc2); |
| } else if (((mod == Cmp_GT_Un) && ((val<=-1)||(val >= 1)))&& |
| ((mod == Cmp_GTE_Un)&& ((val<-1) || (val > 1)))&& |
| ((val == -1) && (mod == Cmp_NE_Un))) { |
| // -1 != test |
| // minint..-2 >u test |
| // 1..maxint >u test |
| // minint..-1 >=u test |
| // 2..maxint >=u test |
| return simplifyCmp3ByResult(src2, false, true, true, |
| newInstType, newmod, newSrc1, newSrc2); |
| } else if (((val == 0) && (mod == Cmp_GT)) || |
| ((val == -1) && ((mod == Cmp_GTE) || |
| (mod == Cmp_EQ)))) { |
| // -1 == test |
| // 0 > test |
| // -1 >= test |
| return simplifyCmp3ByResult(src2, true, false, false, |
| newInstType, newmod, newSrc1, newSrc2); |
| } else if ((val == 0) && (mod == Cmp_NE_Un)) { |
| // 0 != test |
| return simplifyCmp3ByResult(src2, true, false, true, |
| newInstType, newmod, newSrc1, newSrc2); |
| } else if (((val == 1) && (mod == Cmp_NE_Un)) || |
| ((val == 0) && (mod == Cmp_GTE))) { |
| // 1 != test |
| // 0 >= test |
| return simplifyCmp3ByResult(src2, true, true, false, |
| newInstType, newmod, newSrc1, newSrc2); |
| } |
| } |
| } |
| return false; |
| } |
| |
| // simplify some cases of cmp(cmp(), const) |
| bool |
| Simplifier::simplifyCmpOfCmp(Type::Tag instType, |
| ComparisonModifier mod, |
| Opnd* src1, |
| Opnd* src2, |
| Type::Tag &newInstType, |
| ComparisonModifier &newmod, |
| Opnd* &newSrc1, |
| Opnd* &newSrc2) |
| { |
| ConstInst::ConstValue valC; |
| if (ConstantFolder::isConstant(src1->getInst(), valC)) { |
| I_32 val = valC.i4; |
| if (((val == 0) && (mod == Cmp_NE_Un)) || |
| ((val == 1) && (mod == Cmp_EQ))) { |
| // same test as src1; |
| cloneComparison(false, // not negated |
| src2, |
| newInstType, newmod, newSrc1, newSrc2); |
| return true; |
| } else if (((val == 0) && ((mod == Cmp_EQ) || |
| (mod == Cmp_GTE) || |
| (mod == Cmp_GTE_Un))) || |
| ((val == 1) && ((mod == Cmp_NE_Un) || |
| (mod == Cmp_GT) || |
| (mod == Cmp_GT_Un)))) { |
| cloneComparison(true, // negated |
| src2, |
| newInstType, newmod, newSrc1, newSrc2); |
| return true; |
| } |
| } else if (ConstantFolder::isConstant(src2->getInst(), valC)) { |
| I_32 val = valC.i4; |
| if (((val == 0) && ((mod == Cmp_GT) || (mod == Cmp_NE_Un) |
| || (mod == Cmp_GT_Un))) || |
| ((val == 1) && ((mod == Cmp_GTE) || (mod == Cmp_EQ) |
| || (mod == Cmp_GTE_Un)))) { |
| // same test as src1; |
| cloneComparison(false, // not negated |
| src1, |
| newInstType, newmod, newSrc1, newSrc2); |
| return true; |
| } else if (((val == 0) && (mod == Cmp_EQ)) || |
| ((val == 1) && (mod == Cmp_NE_Un))) { |
| // negate src1, by swapping parameters and adjusting test |
| cloneComparison(true, // negated |
| src1, |
| newInstType, newmod, newSrc1, newSrc2); |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| bool |
| Simplifier::simplifyCmpOfAddC(Type::Tag instType, |
| ComparisonModifier mod, |
| Opnd* addOpnd, |
| Opnd* otherOpnd, |
| Type::Tag &newInstType, |
| ComparisonModifier &newmod, |
| Opnd* &newAddSrc, |
| Opnd* &newOtherSrc, |
| bool swapped) |
| { |
| Inst *addInst = addOpnd->getInst(); |
| assert(addInst->getNumSrcOperands() == 2); |
| Opnd *addOp1 = addInst->getSrc(0); |
| Opnd *addOp2 = addInst->getSrc(1); |
| if (haveSameSignedTypes(addOpnd, otherOpnd, addOp1, addOp2, |
| addInst->getOverflowModifier(), |
| mod)) { |
| Opnd *constAddOpnd; |
| Opnd *otherAddOpnd; |
| if (ConstantFolder::isConstant(addOp1)) { |
| constAddOpnd = addOp1; |
| otherAddOpnd = addOp2; |
| } else { |
| constAddOpnd = addOp2; |
| otherAddOpnd = addOp1; |
| } |
| // turn ((x+c1) <> c2) into (x <> (c2-c1)) |
| if (ConstantFolder::isConstant(otherOpnd)) { |
| Type *type2 = addOpnd->getType(); |
| Opnd *newOpnd = |
| fold(Op_Sub, type2, |
| otherOpnd->getInst()->asConstInst(), |
| constAddOpnd->getInst()->asConstInst(), |
| true); |
| newInstType = instType; |
| newmod = mod; |
| newAddSrc = otherAddOpnd; |
| newOtherSrc = newOpnd; |
| return true; |
| } |
| // turn (x >= (y+1)) into (x > y) |
| if (ConstantFolder::isConstantOne(constAddOpnd)) { |
| // turn ((x+1) > y) into (x >= y) |
| if ((mod == Cmp_GT) && !swapped) { |
| newInstType = instType; |
| newmod = Cmp_GTE; |
| newAddSrc = otherAddOpnd; |
| newOtherSrc = otherOpnd; |
| return true; |
| } |
| // turn (x >= (y+1)) into (x > y) |
| if ((mod == Cmp_GTE) && swapped) { |
| newInstType = instType; |
| newmod = Cmp_GT; |
| newAddSrc = otherAddOpnd; |
| newOtherSrc = otherOpnd; |
| return true; |
| } |
| } else if (ConstantFolder::isConstantAllOnes(constAddOpnd)) { |
| // turn ((x-1) >= y) into (x > y) |
| if ((mod == Cmp_GTE) && !swapped) { |
| newInstType = instType; |
| newmod = Cmp_GT; |
| newAddSrc = otherAddOpnd; |
| newOtherSrc = otherOpnd; |
| return true; |
| } |
| // turn (x > (y-1)) into (x >= y) |
| if ((mod == Cmp_GT) && swapped) { |
| newInstType = instType; |
| newmod = Cmp_GTE; |
| newAddSrc = otherAddOpnd; |
| newOtherSrc = otherOpnd; |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| bool |
| Simplifier::simplifyCmpOfSubC(Type::Tag instType, |
| ComparisonModifier mod, |
| Opnd* subOpnd, |
| Opnd* otherOpnd, |
| Type::Tag &newInstType, |
| ComparisonModifier &newmod, |
| Opnd* &newSubSrc, |
| Opnd* &newOtherSrc, |
| bool swapped) |
| { |
| Inst *subInst = subOpnd->getInst(); |
| assert(subInst->getNumSrcOperands() == 2); |
| Opnd *subOp1 = subInst->getSrc(0); |
| Opnd *subOp2 = subInst->getSrc(1); |
| if (haveSameSignedTypes(subOpnd, otherOpnd, subOp1, subOp2, |
| subInst->getOverflowModifier(), |
| mod)) { |
| if (!ConstantFolder::isConstant(subOp2)) |
| return false; |
| |
| Opnd *constSubOpnd = subOp2; |
| Opnd *otherSubOpnd = subOp1; |
| |
| // turn ((x-c1) <> c2) into (x <> (c2+c1)) |
| if (ConstantFolder::isConstant(otherOpnd)) { |
| Type *type2 = subOpnd->getType(); |
| Opnd *newOpnd = |
| fold(Op_Add, type2, |
| otherOpnd->getInst()->asConstInst(), |
| constSubOpnd->getInst()->asConstInst(), |
| true); |
| newInstType = instType; |
| newmod = mod; |
| newSubSrc = otherSubOpnd; |
| newOtherSrc = newOpnd; |
| return true; |
| } |
| // turn (x > (y-1)) into (x >= y) |
| if (ConstantFolder::isConstantOne(constSubOpnd)) { |
| // turn ((x-1) >= y) into (x > y) |
| if ((mod == Cmp_GTE) && !swapped) { |
| newInstType = instType; |
| newmod = Cmp_GT; |
| newSubSrc = otherSubOpnd; |
| newOtherSrc = otherOpnd; |
| return true; |
| } |
| // turn (x > (y-1)) into (x >= y) |
| if ((mod == Cmp_GT) && swapped) { |
| newInstType = instType; |
| newmod = Cmp_GTE; |
| newSubSrc = otherSubOpnd; |
| newOtherSrc = otherOpnd; |
| return true; |
| } |
| } else if (ConstantFolder::isConstantAllOnes(constSubOpnd)) { |
| // turn ((x+1) > y) into (x >= y) |
| if ((mod == Cmp_GT) && !swapped) { |
| newInstType = instType; |
| newmod = Cmp_GTE; |
| newSubSrc = otherSubOpnd; |
| newOtherSrc = otherOpnd; |
| return true; |
| } |
| // turn (x >= (y+1)) into (x > y) |
| if ((mod == Cmp_GTE) && swapped) { |
| newInstType = instType; |
| newmod = Cmp_GT; |
| newSubSrc = otherSubOpnd; |
| newOtherSrc = otherOpnd; |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| bool |
| Simplifier::simplifyCmpOfAddOrSubC(Type::Tag instType, |
| ComparisonModifier mod, |
| Opnd* src1, |
| Opnd* src2, |
| Type::Tag &newInstType, |
| ComparisonModifier &newmod, |
| Opnd* &newSrc1, |
| Opnd* &newSrc2) |
| { |
| |
| Inst *src1Inst = src1->getInst(); |
| if (isAddWithConstant(src1Inst)) { |
| if (simplifyCmpOfAddC(instType, mod, src1, src2, |
| newInstType, newmod, newSrc1, newSrc2, false)) { |
| return true; |
| } |
| } else if (isSubWithConstant(src1Inst)) { |
| if (simplifyCmpOfSubC(instType, mod, src1, src2, |
| newInstType, newmod, newSrc1, newSrc2, false)) { |
| return true; |
| } |
| } |
| Inst *src2Inst = src2->getInst(); |
| if (isAddWithConstant(src2Inst)) { |
| if (simplifyCmpOfAddC(instType, mod, src2, src1, |
| newInstType, newmod, newSrc2, newSrc1, true)) { |
| return true; |
| } |
| } else if (isSubWithConstant(src2Inst)) { |
| if (simplifyCmpOfSubC(instType, mod, src2, src1, |
| newInstType, newmod, newSrc2, newSrc1, true)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| // Returns true if the described comparison can be simplified to a comparison; |
| // if so, fills in the new comparison's modifier, src1, and src2. |
| // Interface is indirect to allow us to use this for Branches, too. |
| // |
| // This is currently used to simplify a comparison of a Cmp3 with a constant. |
| bool |
| Simplifier::simplifyCmpToCmp(Type::Tag instType, |
| ComparisonModifier mod, |
| Opnd* src1, |
| Opnd* src2, |
| Type::Tag &newInstType, |
| ComparisonModifier &newmod, |
| Opnd* &newSrc1, |
| Opnd* &newSrc2) |
| { |
| ConstInst::ConstValue valC; |
| const OptimizerFlags& optimizerFlags = irManager.getOptimizerFlags(); |
| if (optimizerFlags.elim_cmp3 && (instType == Type::Int32) && |
| simplifyCmpOfCmp3(instType, mod, src1, src2, newInstType, newmod, |
| newSrc1, newSrc2)) { |
| return true; |
| } |
| if ((src1->getInst()->getOpcode() == Op_Cmp) || |
| (src2->getInst()->getOpcode() == Op_Cmp)) { |
| if (simplifyCmpOfCmp(instType, mod, src1, src2, newInstType, newmod, |
| newSrc1, newSrc2)) |
| return true; |
| } |
| if (0) { // was: optimizerFlags.brm_debug |
| if (ConstantFolder::isConstantZero(src1)) { |
| newInstType = instType; |
| newSrc1 = src2; |
| newSrc2 = 0; |
| switch (mod) { |
| case Cmp_EQ: newmod = Cmp_Zero; return true; |
| case Cmp_NE_Un: newmod = Cmp_NonZero; return true; |
| case Cmp_GT: break; |
| case Cmp_GT_Un: newmod = Cmp_NonZero; newSrc1 = src1; return true; |
| case Cmp_GTE: break; |
| case Cmp_GTE_Un: newmod = Cmp_Zero; newSrc1 = src2; return true; |
| default: assert(0); break; |
| } |
| } else if (ConstantFolder::isConstantZero(src2)) { |
| newInstType = instType; |
| newSrc1 = src1; |
| newSrc2 = 0; |
| switch (mod) { |
| case Cmp_EQ: newmod = Cmp_Zero; return true; |
| case Cmp_NE_Un: newmod = Cmp_NonZero; return true; |
| case Cmp_GT_Un: break; |
| case Cmp_GT: break; |
| case Cmp_GTE: break; |
| case Cmp_GTE_Un: newmod = Cmp_Zero; newSrc1 = src2; return true; |
| default: assert(0); break; |
| } |
| } |
| } |
| |
| return false; |
| } |
| |
| bool |
| Simplifier::simplifyCmpToCmp(Type::Tag instType, |
| ComparisonModifier mod, |
| Opnd* src1, |
| Type::Tag &newInstType, |
| ComparisonModifier &newmod, |
| Opnd* &newSrc1) |
| { |
| Inst *srci = src1->getInst(); |
| if (srci->getOpcode() == Op_TauStaticCast) { |
| newInstType = instType; |
| newSrc1 = srci->getSrc(0); |
| newmod = mod; |
| return true; |
| } |
| return false; |
| } |
| |
| bool |
| Simplifier::canFoldBranch(Type::Tag instType, |
| ComparisonModifier mod, |
| Opnd* src1, |
| Opnd* src2, |
| bool& isTaken) { |
| ConstInst::ConstValue val1, val2; |
| if (ConstantFolder::isConstant(src1->getInst(), val1) && |
| ConstantFolder::isConstant(src2->getInst(), val2)) { |
| // this branch can be folded |
| ConstInst::ConstValue result; |
| if (ConstantFolder::foldCmp(instType, mod, val1, val2, result)) { |
| if (result.i4 == 0) { |
| // branch not taken |
| isTaken = false; |
| } else { |
| // branch taken |
| isTaken = true; |
| } |
| return true; |
| } |
| } else if(src1 == src2) { |
| if(src1->getType()->isFloatingPoint()) |
| // We can't assume x == x. E.g., Nan != Nan |
| return false; |
| switch (mod) { |
| case Cmp_EQ: |
| case Cmp_GTE: |
| case Cmp_GTE_Un: |
| isTaken = true; |
| return true; |
| case Cmp_NE_Un: |
| case Cmp_GT: |
| case Cmp_GT_Un: |
| isTaken = false; |
| return true; |
| default: |
| break; |
| } |
| } else if (Type::isVTablePtr(instType)) { |
| Inst* src1DefInst = propagateCopy(src1)->getInst(); |
| Inst* src2DefInst = propagateCopy(src2)->getInst(); |
| if (src1DefInst->getOpcode() == Op_GetVTableAddr && src2DefInst->getOpcode() == Op_GetVTableAddr) { |
| Type* src1ObjType = src1DefInst->asTypeInst()->getTypeInfo(); |
| Type* src2ObjType = src2DefInst->asTypeInst()->getTypeInfo(); |
| if (!src1ObjType->isUnresolvedType() && !src2ObjType->isUnresolvedType()) { |
| isTaken = (src1ObjType == src2ObjType && mod == Cmp_EQ) |
| || (src1ObjType != src2ObjType && mod == Cmp_NE_Un); |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| bool |
| Simplifier::simplifyBranch(Type::Tag instType, |
| ComparisonModifier mod, |
| LabelInst* label, |
| Opnd* src1, |
| Opnd* src2) |
| { |
| // try to simplify to a simpler comparison |
| ComparisonModifier newMod; |
| Type::Tag newInstType; |
| Opnd *newSrc1; |
| Opnd *newSrc2; |
| if (simplifyCmpToCmp(instType, mod, src1, src2, |
| newInstType, newMod, newSrc1, newSrc2)) { |
| // can simplify it. |
| if (newSrc2) { |
| genBranch(newInstType, newMod, label, newSrc1, newSrc2); |
| } else { |
| genBranch(newInstType, newMod, label, newSrc1); |
| } |
| return true; |
| } |
| return false; |
| } |
| |
| bool |
| Simplifier::simplifyBranch(Type::Tag instType, |
| ComparisonModifier mod, |
| LabelInst* label, |
| Opnd* src1) |
| { |
| // try to simplify to a simpler comparison |
| ComparisonModifier newMod; |
| Type::Tag newInstType; |
| Opnd *newSrc1; |
| if (simplifyCmpToCmp(instType, mod, src1, |
| newInstType, newMod, newSrc1)) { |
| // can simplify it. |
| genBranch(newInstType, newMod, label, newSrc1); |
| return true; |
| } |
| return false; |
| } |
| |
| |
| bool |
| Simplifier::canFoldBranch(Type::Tag instType, |
| ComparisonModifier mod, |
| Opnd* src, |
| bool& isTaken) { |
| ConstInst::ConstValue val; |
| if (ConstantFolder::isConstant(src->getInst(), val)) { |
| ConstInst::ConstValue result; |
| if (ConstantFolder::foldCmp(instType, mod, val, result)) { |
| if (result.i4 == 0) { |
| // branch not taken |
| isTaken = false; |
| } else { |
| // branch taken |
| isTaken = true; |
| } |
| return true; |
| } |
| } else if (isNonNullObject(src)) { |
| if(mod == Cmp_Zero) { |
| // branch not taken |
| isTaken = false; |
| } else { |
| // branch taken |
| isTaken = true; |
| } |
| return true; |
| } |
| return false; |
| } |
| |
| bool |
| Simplifier::simplifySwitch(U_32 numLabels, |
| LabelInst* label[], |
| LabelInst* defaultLabel, |
| Opnd* src) { |
| assert(numLabels > 0); |
| // check for just 1 target |
| LabelInst* label1 = label[0]; |
| U_32 i; |
| for (i = 1; i<numLabels; i++) { |
| if (label[i] != label1) return false; // we have >1 distinct labels |
| } |
| // have just 1 target; |
| Opnd* numTargets = genLdConstant((I_32) numLabels)->getDst(); |
| genBranch(Type::Int32, Cmp_GT_Un, label1, numTargets, src); |
| return true; |
| } |
| //----------------------------------------------------------------------------- |
| // Runtime check simplifications |
| //----------------------------------------------------------------------------- |
| |
| // These all return a tau normally. If we can tell that they will always pass, |
| // then returns the destination of a tauSafe() operation. If we can tell that they |
| // will always fail, these methods return an original dstOpnd. (This can be |
| // used eventually to insert a throw.) Otherwise, returns NULL. |
| |
| Opnd* |
| Simplifier::simplifyTauCheckNull(Opnd* opnd, bool &alwaysThrows) { |
| if (isNonNullObject(opnd)) |
| return genTauSafe()->getDst(); // is safe by construction |
| if (isNonNullParameter(opnd)) { |
| return genTauIsNonNull(opnd)->getDst(); // is safe, but only in method |
| } |
| if (isNullObject(opnd)) { |
| if (Log::isEnabled()) { |
| Log::out() << "CheckNull of src "; |
| opnd->print(Log::out()); |
| Log::out() << " always throws" << ::std::endl; |
| } |
| genThrowSystemException(CompilationInterface::Exception_NullPointer); |
| alwaysThrows = true; |
| return genTauUnsafe()->getDst(); |
| } |
| return NULL; |
| } |
| |
| Opnd* |
| Simplifier::simplifyTauCheckBounds(Opnd* arrayLen, Opnd* index, bool &alwaysThrows) { |
| // check if array was created with constant length |
| // e.g., newarray with a constant length parameter |
| ConstInst* constArrayLen = arrayLen->getInst()->asConstInst(); |
| ConstInst* constIndex = index->getInst()->asConstInst(); |
| if (constArrayLen && constIndex) { |
| // compare the constant size and index |
| I_32 result = 0; |
| I_32 lenv = constArrayLen->getValue().i4; |
| I_32 idxv = constIndex->getValue().i4; |
| if (ConstantFolder::foldCmp32(Cmp_GT_Un, |
| lenv, idxv, result)) { |
| if (result == 1) { |
| // index is smaller than size, remove check |
| return genTauSafe()->getDst(); // is safe by construction |
| } else { |
| // fold to a throwSystemId |
| if (Log::isEnabled()) { |
| Log::out() << "Checkbounds of arrayLen "; |
| arrayLen->print(Log::out()); |
| Log::out() << " and index "; |
| index->print(Log::out()); |
| Log::out() << " equivalent to testing (" |
| << (int)lenv << " GTU " << (int)idxv |
| << ") = " << (int) result |
| << ", and always throws" << ::std::endl; |
| } |
| genThrowSystemException(CompilationInterface::Exception_ArrayIndexOutOfBounds); |
| alwaysThrows = true; |
| return genTauUnsafe()->getDst(); |
| } |
| } |
| } |
| return NULL; |
| } |
| |
| Opnd* |
| Simplifier::simplifyTauCheckLowerBound(Opnd* lb, Opnd *idx, bool &alwaysThrows) { |
| ConstInst* constLB = lb->getInst()->asConstInst(); |
| ConstInst* constIndex = idx->getInst()->asConstInst(); |
| if (constLB != NULL && constIndex != NULL) { |
| // compare the constant size and index |
| I_32 result = 0; |
| I_32 lbv = constLB->getValue().i4; |
| I_32 idxv = constIndex->getValue().i4; |
| if (ConstantFolder::foldCmp32(Cmp_GT, |
| lbv, |
| idxv, |
| result)) { |
| if (result == 1) { |
| // fold to a throwSystemId |
| if (Log::isEnabled()) { |
| Log::out() << "CheckLowerBound of lb "; |
| lb->print(Log::out()); |
| Log::out() << " and index "; |
| idx->print(Log::out()); |
| Log::out() << " equivalent to testing (" |
| << (int)lbv << " GT " << (int)idxv |
| << ") = " << (int) result |
| << ", and always throws" << ::std::endl; |
| } |
| genThrowSystemException(CompilationInterface::Exception_ArrayIndexOutOfBounds); |
| alwaysThrows = true; |
| return genTauUnsafe()->getDst(); |
| } else { |
| // index is smaller than size, remove check |
| return genTauSafe()->getDst(); // is safe by construction |
| } |
| } |
| } |
| return NULL; |
| } |
| |
| |
| Opnd* |
| Simplifier::simplifyTauCheckUpperBound(Opnd* idx, Opnd* ub, bool &alwaysThrows) { |
| // check if both happen to be constant |
| // which is pretty unlikely, since only ABCD inserts this instruction, |
| // and it's pretty smart. |
| ConstInst* constUB = ub->getInst()->asConstInst(); |
| ConstInst* constIndex = idx->getInst()->asConstInst(); |
| if (constUB != NULL && constIndex != NULL) { |
| // compare the constant size and index |
| I_32 result = 0; |
| I_32 idxv = constIndex->getValue().i4; |
| I_32 ubv = constUB->getValue().i4; |
| if (ConstantFolder::foldCmp32(Cmp_GT, |
| ubv, |
| idxv, |
| result)) { |
| if (result == 1) { |
| // index is smaller than size, remove check |
| return genTauSafe()->getDst(); // check is safe by construction |
| } else { |
| // fold to a throwSystemId |
| if (Log::isEnabled()) { |
| Log::out() << "CheckUpperBound of idx "; |
| idx->print(Log::out()); |
| Log::out() << " and ub "; |
| ub->print(Log::out()); |
| Log::out() << " equivalent to testing NOT(" |
| << (int)ubv << " GT " << (int)idxv |
| << ") = " << (int) result |
| << ", and always throws" << ::std::endl; |
| } |
| genThrowSystemException(CompilationInterface::Exception_ArrayIndexOutOfBounds); |
| alwaysThrows = true; |
| return genTauUnsafe()->getDst(); |
| } |
| } |
| } |
| return NULL; |
| } |
| |
| |
| // |
| // looks for a load of a non-zero constant |
| // |
| Opnd* |
| Simplifier::simplifyTauCheckZero(Opnd* opnd, bool &alwaysThrows) { |
| I_32 value; |
| if (ConstantFolder::isConstant(opnd->getInst(), value)) { |
| if (value != 0) |
| return genTauSafe()->getDst(); // check is safe by construction |
| else { |
| if (Log::isEnabled()) { |
| Log::out() << "CheckZero of opnd "; |
| opnd->print(Log::out()); |
| Log::out()<< " always throws" << ::std::endl; |
| } |
| genThrowSystemException(CompilationInterface::Exception_DivideByZero); |
| alwaysThrows = true; |
| return genTauUnsafe()->getDst(); |
| } |
| } |
| return NULL; |
| } |
| |
| // |
| // simplify check if either operand is known |
| // |
| Opnd* |
| Simplifier::simplifyTauCheckDivOpnds(Opnd* src1, Opnd* src2, bool &alwaysThrows) { |
| // look for anything other than src1=MAXNEGINT, src2=-1 |
| I_32 value; |
| bool elim = false; |
| if (ConstantFolder::isConstant(src1->getInst(), value)) { |
| if ((U_32)value != 0x80000000) { |
| // overflow can't happen |
| elim = true; |
| } else if (ConstantFolder::isConstant(src2->getInst(), value) && |
| (value == -1)) { |
| // overflow will happen for sure |
| alwaysThrows = true; |
| return genTauUnsafe()->getDst(); |
| } |
| } else if (ConstantFolder::isConstant(src2->getInst(), value) |
| && (value != -1)) { |
| elim = true; |
| } |
| if (!elim) { |
| // above constant folders return false if opnd is not I_32 |
| // try int64 instead |
| int64 value64; |
| if (ConstantFolder::isConstant(src1->getInst(), value64)) { |
| if ((uint64)value64 != __INT64_C(0x8000000000000000)) { |
| // overflow can't happen |
| elim = true; |
| } else if (ConstantFolder::isConstant(src2->getInst(), value64) |
| && (value64 == __INT64_C(-1))) { |
| // overflow will happen for sure |
| alwaysThrows = true; |
| return genTauUnsafe()->getDst(); |
| } |
| } else if (ConstantFolder::isConstant(src2->getInst(), value64) |
| && (value64 != __INT64_C(-1))) |
| elim = true; |
| } |
| if (elim) { |
| return genTauSafe()->getDst(); // check is safe by construction |
| } |
| return NULL; |
| } |
| |
| // |
| // looks for a load of a constant which is definitely finite |
| // (not NaN, +infinity, or -infinity) |
| // |
| Opnd* |
| Simplifier::simplifyTauCheckFinite(Opnd* opnd, bool &alwaysThrows) { |
| Type *opType = opnd->getType(); |
| ConstInst::ConstValue value; |
| if (ConstantFolder::isConstant(opnd->getInst(), value)) { |
| switch (opType->tag) { |
| case Type::Single: // single |
| { |
| float s = value.s; |
| if (!finite((double)s)) { |
| alwaysThrows = true; |
| return genTauUnsafe()->getDst(); |
| } |
| break; |
| } |
| case Type::Double: |
| { |
| double d = value.d; |
| if (!finite(d)) { |
| alwaysThrows = true; |
| return genTauUnsafe()->getDst(); |
| } |
| break; |
| } |
| case Type::Float: |
| default: |
| return NULL; |
| } |
| return genTauSafe()->getDst(); // safe by construction |
| } else |
| return NULL; |
| } |
| |
| //----------------------------------------------------------------------------- |
| // Type checking simplifications |
| //----------------------------------------------------------------------------- |
| Opnd* |
| Simplifier::simplifyTauCast(Opnd* src, Opnd *tauCheckedNull, Type* castType) { |
| Type *opndType = src->getType(); |
| if (isNullObject(src) || |
| irManager.getTypeManager().isResolvedAndSubClassOf(opndType, castType)) { |
| return genTauStaticCast(src, tauCheckedNull, castType)->getDst(); |
| } |
| return NULL; |
| } |
| |
| Opnd* |
| Simplifier::simplifyTauAsType(Opnd* src, Opnd* tauCheckedNull, Type* type) { |
| Type* srcType = src->getType(); |
| if (isNullObject(src) || |
| irManager.getTypeManager().isResolvedAndSubClassOf(srcType, type)) |
| return src; |
| if (isExactType(src) && |
| !irManager.getTypeManager().isResolvedAndSubClassOf(srcType, type)) { |
| ConstInst::ConstValue val; |
| val.i = NULL; |
| return genLdConstant(irManager.getTypeManager().getNullObjectType(), |
| val)->getDst(); |
| } |
| return NULL; |
| } |
| |
| Opnd* |
| Simplifier::simplifyTauInstanceOf(Opnd* src, Opnd* tauCheckedNull, Type* type) { |
| Type *srcType = src->getType(); |
| |
| bool srcIsNonNull = (tauCheckedNull->getInst()->getOpcode() != Op_TauUnsafe); |
| if (srcIsNonNull && |
| irManager.getTypeManager().isResolvedAndSubClassOf(srcType, type)) { |
| return genLdConstant((I_32)1)->getDst(); |
| } |
| |
| // If src is definitely a null object, then the result is 0. |
| if ((!srcIsNonNull) && isNullObject(src)) { |
| return genLdConstant((I_32)0)->getDst(); |
| } |
| |
| if (isExactType(src) && |
| !irManager.getTypeManager().isResolvedAndSubClassOf(srcType, type)) |
| return genLdConstant((I_32)0)->getDst(); |
| |
| return NULL; |
| } |
| |
| Opnd* |
| Simplifier::simplifyTauCheckElemType(Opnd* arrayBase, Opnd* src, bool &alwaysThrows) { |
| if (isNullObject(src)) |
| return genTauSafe()->getDst(); // always safe to store null |
| assert(arrayBase->getType()->isArrayType()); |
| Type *arrayElemType = ((ArrayType*)arrayBase->getType())->getElementType(); |
| if (isExactType(arrayBase) && |
| irManager.getTypeManager().isResolvedAndSubClassOf(src->getType(), arrayElemType)) { |
| return genTauHasExactType(arrayBase,arrayBase->getType())->getDst(); |
| } |
| // check to see if src was loaded from arrayBase |
| if (src->getInst()->getOpcode() == Op_TauLdInd) { |
| // src was loaded from memory |
| Opnd* ptr = src->getInst()->getSrc(0); |
| while (ptr->getInst()->getOpcode() == Op_AddScaledIndex) { |
| // ptr is a ptr into an array |
| ptr = ptr->getInst()->getSrc(0); |
| } |
| if (ptr->getInst()->getOpcode() == Op_LdArrayBaseAddr) { |
| // ptr is an array base address |
| Opnd* srcBase = ptr->getInst()->getSrc(0); |
| if (srcBase == arrayBase) { |
| return genTauSafe()->getDst(); // is safe, was loaded from same array |
| } |
| } |
| } |
| return NULL; |
| } |
| |
| //----------------------------------------------------------------------------- |
| // Array access simplifications |
| //----------------------------------------------------------------------------- |
| Opnd* |
| Simplifier::simplifyTauArrayLen(Type* dstType, Type::Tag type, Opnd* base) { |
| return getArraySize(base); |
| } |
| |
| Opnd* |
| Simplifier::simplifyTauArrayLen(Type* dstType, Type::Tag type, Opnd* base, |
| Opnd* tauNullChecked, Opnd *tauTypeChecked) { |
| return getArraySize(base); |
| } |
| |
| Opnd* |
| Simplifier::simplifyAddScaledIndex(Opnd* base, Opnd* index) { |
| ConstInst* constIndexInst = index->getInst()->asConstInst(); |
| if ( constIndexInst != NULL ) { |
| assert(index->getType()->isInteger()); |
| if (constIndexInst->getValue().i8 == 0) |
| return base; |
| } |
| return NULL; |
| } |
| |
| // |
| // Compressed reference operations |
| // |
| |
| Opnd* |
| Simplifier::simplifyUncompressRef(Opnd* opnd) { |
| Inst *opndInst = opnd->getInst(); |
| if (opndInst->getOpcode() == Op_CompressRef) { |
| Opnd *uncompRef = opndInst->getSrc(0); |
| return uncompRef; |
| } |
| if (opndInst->getOpcode() == Op_LdConstant) { |
| Type::Tag opndType = opndInst->getType(); |
| if (opndType == Type::CompressedNullObject) { |
| // create an uncompressed null instead |
| return genLdConstant(irManager.getTypeManager().getNullObjectType(), |
| ConstInst::ConstValue())->getDst(); |
| } |
| } |
| return NULL; |
| } |
| |
| Opnd* |
| Simplifier::simplifyCompressRef(Opnd* opnd) { |
| Inst *opndInst = opnd->getInst(); |
| if (opndInst->getOpcode() == Op_UncompressRef) { |
| Opnd *compRef = opndInst->getSrc(0); |
| return compRef; |
| } |
| if (opndInst->getOpcode() == Op_LdConstant) { |
| Type::Tag opndType = opndInst->getType(); |
| if (opndType == Type::NullObject) { |
| // create a compressed null instead |
| return genLdConstant(irManager.getTypeManager().getCompressedNullObjectType(), |
| ConstInst::ConstValue())->getDst(); |
| } |
| } |
| return NULL; |
| } |
| |
| Opnd* |
| Simplifier::simplifyAddOffset(Type *ptrType, Opnd* uncompBase, Opnd *offset) { |
| const OptimizerFlags& optimizerFlags = irManager.getOptimizerFlags(); |
| if (optimizerFlags.reduce_compref) { |
| Inst *uncompBaseInst = uncompBase->getInst(); |
| if (uncompBaseInst->getOpcode() == Op_UncompressRef) { |
| // try to convert to addOffsetPlusHeapbase |
| Inst *offsetInst = offset->getInst(); |
| Inst *offsetPlusHeapbaseInst = 0; |
| switch (offsetInst->getOpcode()) { |
| case Op_LdFieldOffset: |
| { |
| FieldAccessInst *fainst = offsetInst->asFieldAccessInst(); |
| FieldDesc *fd = fainst->getFieldDesc(); |
| offsetPlusHeapbaseInst = genLdFieldOffsetPlusHeapbase(fd); |
| break; |
| } |
| case Op_LdArrayBaseOffset: |
| { |
| TypeInst *tinst = offsetInst->asTypeInst(); |
| Type *elemType = tinst->getTypeInfo(); |
| offsetPlusHeapbaseInst = genLdArrayBaseOffsetPlusHeapbase(elemType); |
| break; |
| } |
| case Op_LdArrayLenOffset: |
| { |
| TypeInst *tinst = offsetInst->asTypeInst(); |
| Type *elemType = tinst->getTypeInfo(); |
| offsetPlusHeapbaseInst = genLdArrayLenOffsetPlusHeapbase(elemType); |
| break; |
| } |
| default: |
| break; |
| } |
| if (offsetPlusHeapbaseInst) { |
| Opnd *offsetPlusHeapbaseOpnd = offsetPlusHeapbaseInst->getDst(); |
| Opnd *compBase = uncompBaseInst->getSrc(0); |
| Inst *addOffsetPlusHeapbaseInst |
| = genAddOffsetPlusHeapbase(ptrType, |
| compBase, |
| offsetPlusHeapbaseOpnd); |
| Opnd *result = addOffsetPlusHeapbaseInst->getDst(); |
| return result; |
| } |
| } |
| if (0 && theReassociate) { |
| Opnd *opnd = simplifyAddOffsetViaReassociation(uncompBase, offset); |
| return opnd; |
| } |
| } |
| return NULL; |
| } |
| |
| Opnd* |
| Simplifier::simplifyAddOffsetPlusHeapbase(Type *ptrType, |
| Opnd* compBase, |
| Opnd *offsetPlusHeapbase) { |
| const OptimizerFlags& optimizerFlags = irManager.getOptimizerFlags(); |
| if (0 && optimizerFlags.reduce_compref && theReassociate) { |
| Opnd *opnd = simplifyAddOffsetPlusHeapbaseViaReassociation(compBase, |
| offsetPlusHeapbase); |
| return opnd; |
| } |
| return NULL; |
| } |
| |
| // |
| // Store simplifications |
| // |
| |
| // if compressRef, then this is a store into the heap, so if it's a reference, |
| // it should be compressed |
| Opnd * |
| SimplifierWithInstFactory::simplifyStoreSrc(Opnd* src, Type::Tag &typetag, |
| Modifier &mod, |
| bool compressRef) |
| { |
| Inst *srci = src->getInst(); |
| if ((srci->getOpcode() == Op_Conv) && |
| (typetag == srci->getType())) { |
| Opnd *srcisrc = srci->getSrc(0); |
| if (srcisrc->getType()->tag == src->getType()->tag) |
| return srcisrc; |
| } |
| |
| const OptimizerFlags& optimizerFlags = irManager.getOptimizerFlags(); |
| |
| if (compressRef && |
| optimizerFlags.reduce_compref && |
| (mod.getAutoCompressModifier() == AutoCompress_Yes)) { |
| |
| Type *srcType = src->getType(); |
| assert(srcType->isReference()); |
| assert(!srcType->isCompressedReference()); |
| |
| Type *newSrcType = typeManager.compressType(srcType); |
| Modifier newMod = (Modifier(mod.getStoreModifier()) | |
| Modifier(AutoCompress_No)); |
| Opnd *compressedSrc = genCompressRef(src)->getDst(); |
| |
| typetag = newSrcType->tag; |
| mod = newMod; |
| return compressedSrc; |
| } |
| |
| return 0; |
| } |
| |
| void |
| Simplifier::simplifyTauStStatic(Inst *inst) |
| { |
| if (Log::isEnabled()) { |
| Log::out() << "Trying to simplify TauStStatic: "; |
| inst->print(Log::out()); |
| Log::out() << ::std::endl; |
| } |
| FieldAccessInst *fieldInst = inst->asFieldAccessInst(); |
| assert(fieldInst); |
| Type::Tag typetag = fieldInst->getType(); |
| Modifier mod = fieldInst->getModifier(); |
| assert(inst->getNumSrcOperands() == 2); |
| Opnd *src = fieldInst->getSrc(0); |
| |
| Opnd *newSrc = simplifyStoreSrc(src, typetag, mod, true); |
| if (newSrc) { |
| inst->setSrc(0, newSrc); |
| inst->setType(typetag); |
| inst->setModifier(mod); |
| } |
| } |
| |
| void |
| Simplifier::simplifyTauStField(Inst *inst) |
| { |
| if (Log::isEnabled()) { |
| Log::out() << "Trying to simplify StField: "; |
| inst->print(Log::out()); |
| Log::out() << ::std::endl; |
| } |
| FieldAccessInst *fieldInst = inst->asFieldAccessInst(); |
| assert(fieldInst); |
| Type::Tag typetag = fieldInst->getType(); |
| Modifier mod = fieldInst->getModifier(); |
| assert(inst->getNumSrcOperands() == 4); |
| Opnd *src = fieldInst->getSrc(0); // src |
| |
| Opnd *newSrc = simplifyStoreSrc(src, typetag, mod, true); |
| if (newSrc) { |
| inst->setSrc(0, newSrc); |
| inst->setType(typetag); |
| inst->setModifier(mod); |
| } |
| } |
| |
| void |
| Simplifier::simplifyTauStInd(Inst *inst) |
| { |
| |
| Modifier mod = inst->getModifier(); |
| Type::Tag typetag = inst->getType(); |
| assert(inst->getNumSrcOperands() == 5); |
| Opnd *src = inst->getSrc(0); |
| Opnd *ptr = inst->getSrc(1); |
| |
| Type *ptrType = ptr->getType(); |
| assert(ptrType->isPtr()); |
| Type *fieldType = ((PtrType *)ptrType)->getPointedToType(); |
| |
| Opnd *newSrc = simplifyStoreSrc(src, typetag, mod, |
| fieldType->isCompressedReference()); |
| if (newSrc) { |
| inst->setSrc(0, newSrc); |
| inst->setType(typetag); |
| inst->setModifier(mod); |
| } |
| } |
| |
| |
| void |
| Simplifier::simplifyTauStElem(Inst *inst) |
| { |
| Modifier mod = inst->getModifier(); |
| Type::Tag typetag = inst->getType(); |
| assert(inst->getNumSrcOperands() == 6); |
| Opnd *src = inst->getSrc(0); |
| |
| Opnd *newSrc = simplifyStoreSrc(src, typetag, mod, true); |
| if (newSrc) { |
| inst->setSrc(0, newSrc); |
| inst->setType(typetag); |
| inst->setModifier(mod); |
| } |
| } |
| |
| void |
| Simplifier::simplifyTauStRef(Inst *inst) |
| { |
| Type::Tag typetag = inst->getType(); |
| Modifier mod = inst->getModifier(); |
| assert(inst->getNumSrcOperands() == 6); |
| Opnd *src = inst->getSrc(0); |
| Opnd *pointer = inst->getSrc(1); |
| |
| Type *ptrType = pointer->getType(); |
| assert(ptrType->isPtr()); |
| Type *fieldType = ((PtrType *)ptrType)->getPointedToType(); |
| |
| Opnd *newSrc = simplifyStoreSrc(src, typetag, mod, |
| fieldType->isCompressedReference()); |
| if (newSrc) { |
| inst->setSrc(0, newSrc); |
| inst->setType(typetag); |
| inst->setModifier(mod); |
| } |
| } |
| |
| Opnd * |
| Simplifier::simplifyTauLdInd(Modifier mod, Type* dstType, Type::Tag type, Opnd *ptr, |
| Opnd *tauBaseNonNull, Opnd *tauAddressInRange) |
| { |
| const OptimizerFlags& optimizerFlags = irManager.getOptimizerFlags(); |
| if (optimizerFlags.do_sxt && !optimizerFlags.ia32_code_gen) { |
| // simplify signed loads to unsigned |
| Opnd *newLd = 0; |
| switch (type) { |
| case Type::Int8: |
| newLd = genTauLdInd(mod, dstType, Type::UInt8, ptr, |
| tauBaseNonNull, tauAddressInRange)->getDst(); |
| break; |
| case Type::Int16: |
| newLd = genTauLdInd(mod, dstType, Type::UInt16, ptr, |
| tauBaseNonNull, tauAddressInRange)->getDst(); |
| break; |
| case Type::Int32: |
| newLd = genTauLdInd(mod, dstType, Type::UInt32, ptr, |
| tauBaseNonNull, tauAddressInRange)->getDst(); |
| break; |
| default: |
| break; |
| } |
| if (newLd) { |
| Opnd *extOpnd = genConv(dstType, type, Modifier(Overflow_None)|Modifier(Exception_Never)|Modifier(Strict_No), newLd)->getDst(); |
| return extOpnd; |
| } |
| } |
| if (optimizerFlags.reduce_compref && |
| (mod.getAutoCompressModifier() == AutoCompress_Yes)) { |
| |
| assert(dstType->isReference()); |
| assert(!dstType->isCompressedReference()); |
| Type *compressedType = irManager.getTypeManager().compressType(dstType); |
| Type *ptrType = ptr->getType(); |
| if( !(ptrType->isPtr()) ) assert(0); |
| Type *fieldType = ((PtrType *)ptrType)->getPointedToType(); |
| if( !(fieldType->isCompressedReference()) ) assert(0); |
| |
| Opnd *newLd = genTauLdInd(AutoCompress_No, compressedType, |
| compressedType->tag, ptr, |
| tauBaseNonNull, tauAddressInRange)->getDst(); |
| Opnd *uncOpnd = genUncompressRef(newLd)->getDst(); |
| return uncOpnd; |
| } |
| return 0; |
| } |
| |
| |
| Opnd * |
| Simplifier::simplifyLdRef(Modifier mod, Type* dstType, |
| U_32 token, MethodDesc* enclosingMethod) |
| { |
| const OptimizerFlags& optimizerFlags = irManager.getOptimizerFlags(); |
| if (optimizerFlags.reduce_compref && |
| (mod.getAutoCompressModifier() == AutoCompress_Yes)) { |
| |
| assert(dstType->isReference()); |
| assert(!dstType->isCompressedReference()); |
| Type *compressedType = irManager.getTypeManager().compressType(dstType); |
| Opnd *newLdRef = genLdRef(AutoCompress_No, compressedType, |
| token, |
| enclosingMethod)->getDst(); |
| Opnd *uncOpnd = genUncompressRef(newLdRef)->getDst(); |
| return uncOpnd; |
| } |
| return 0; |
| } |
| |
| |
| //----------------------------------------------------------------------------- |
| // Method call related simplifications |
| //----------------------------------------------------------------------------- |
| Opnd* |
| Simplifier::simplifyTauLdVirtFunAddr(Opnd* vtable, Opnd *tauVtableHasMethod, |
| MethodDesc* methodDesc) { |
| Inst* ldVTableInst = vtable->getInst(); |
| if (ldVTableInst->getOpcode() == Op_TauLdVTableAddr || |
| ldVTableInst->getOpcode() == Op_TauLdIntfcVTableAddr) { |
| Opnd* baseRef = ldVTableInst->getSrc(0); |
| if (isExactType(baseRef)) { |
| } |
| } else { |
| assert(0); |
| } |
| return NULL; |
| } |
| |
| Opnd* |
| Simplifier::simplifyTauLdVirtFunAddrSlot(Opnd* vtable, Opnd *tauVtableHasMethod, |
| MethodDesc* methodDesc) { |
| // if vtable class is exact or final then change this |
| // to a ldvirtfunaddrslot |
| // if vtable is an interface vtable and the base of that |
| // interface vtable is exact or final then change this |
| // to a ldvirtfunaddrslot |
| // if vtable is of exact type (loaded by getvtable) then |
| // change this to a ldvirtfunaddrslot |
| Inst* ldVTableInst = vtable->getInst(); |
| Type* baseType = NULL; |
| if (ldVTableInst->getOpcode() == Op_TauLdVTableAddr || |
| ldVTableInst->getOpcode() == Op_TauLdIntfcVTableAddr) { |
| Opnd* baseRef = ldVTableInst->getSrc(0); |
| if (isExactType(baseRef)) { |
| // base has exact type |
| baseType = baseRef->getType(); |
| } |
| } else if (ldVTableInst->getOpcode() == Op_GetVTableAddr) { |
| TypeInst* typeInst = ldVTableInst->asTypeInst(); |
| assert(typeInst != NULL); |
| baseType = typeInst->getTypeInfo(); |
| } |
| if (baseType != NULL) { |
| MethodDesc* newMethodDesc = |
| irManager.getCompilationInterface().getOverridingMethod((NamedType*)baseType, methodDesc); |
| if (newMethodDesc) { |
| // change to ldvirtfunaddrslot of newMethodDesc |
| return genLdFunAddrSlot(newMethodDesc)->getDst(); |
| } |
| |
| } |
| return NULL; |
| } |
| |
| Opnd* |
| Simplifier::simplifyTauLdIntfcVTableAddr(Opnd* base, Type* vtableType) { |
| // Can't really simplify load of an interface vtable |
| return NULL; |
| } |
| |
| Opnd* |
| Simplifier::simplifyTauLdVTableAddr(Opnd* base, Opnd *tauBaseNonNull) { |
| if(isExactType(base)) { |
| Type* type = base->getType(); |
| assert((type->isClass() && !type->isAbstract()) || type->isArray()); |
| return genGetVTableAddr((ObjectType*) type)->getDst(); |
| } |
| return NULL; |
| } |
| |
| Opnd* |
| Simplifier::simplifyTauVirtualCall(MethodDesc* methodDesc, |
| Type* returnType, |
| Opnd* tauNullCheckedFirstArg, |
| Opnd* tauTypesChecked, |
| U_32 numArgs, |
| Opnd* args[]) |
| { |
| // |
| // change to a direct call if the type of the this pointer is exactly known |
| // or if the method is final |
| // |
| if (isExactType(args[0]) || methodDesc->isFinal() || methodDesc->isPrivate()) { |
| if(isExactType(args[0]) && !args[0]->getType()->isInterface()) { |
| methodDesc = irManager.getCompilationInterface().getOverridingMethod( |
| (NamedType*) args[0]->getType(), methodDesc); |
| } |
| if (methodDesc == NULL || methodDesc->getParentType()->isValue()) { |
| return NULL; |
| } |
| return genDirectCall(methodDesc, returnType, |
| tauNullCheckedFirstArg, tauTypesChecked, |
| numArgs, args)->getDst(); |
| } |
| return NULL; |
| } |
| Inst* |
| Simplifier::simplifyIndirectCallInst( Opnd* funPtr, |
| Type* returnType, |
| Opnd* tauNullCheckedFirstArg, |
| Opnd* tauTypesChecked, |
| U_32 numArgs, |
| Opnd** args) |
| { |
| return simplifyIndirectMemoryCallInst(funPtr, returnType, |
| tauNullCheckedFirstArg, tauTypesChecked, |
| numArgs, args); |
| } |
| |
| Inst* |
| Simplifier::simplifyIndirectMemoryCallInst(Opnd* funPtr, |
| Type* returnType, |
| Opnd* tauNullCheckedFirstArg, |
| Opnd* tauTypesChecked, |
| U_32 numArgs, |
| Opnd** args) |
| { |
| // if funptr is a load of a fun slot that does not go through a vtable, then |
| // simplify this to a direct call if direct calls are enabled |
| MethodInst* ldFunInst = funPtr->getInst()->asMethodInst(); |
| if (ldFunInst == NULL) { |
| return NULL; |
| } |
| if (ldFunInst->getOpcode() == Op_LdFunAddrSlot) { |
| return genDirectCall(ldFunInst->getMethodDesc(), returnType, |
| tauNullCheckedFirstArg, tauTypesChecked, |
| numArgs, args); |
| } |
| return NULL; |
| } |
| |
| Opnd* |
| Simplifier::simplifyTauAnd(MultiSrcInst *inst) |
| { |
| U_32 nsrcs = inst->getNumSrcOperands(); |
| U_32 nsrcs0 = nsrcs; |
| { |
| for (U_32 i = 0; i < nsrcs; ++i) { |
| Opnd *srci = inst->getSrc(i); |
| Opcode opcode = srci->getInst()->getOpcode(); |
| if (opcode == Op_TauUnsafe) { |
| return srci; |
| } else if (opcode == Op_TauSafe) { |
| // swap with last and decrease number |
| nsrcs -= 1; |
| if (i < nsrcs) { |
| Opnd *lastOpnd = inst->getSrc(nsrcs); |
| inst->setSrc(nsrcs, srci); |
| inst->setSrc(i, lastOpnd); |
| i -= 1; // re-examine that opnd |
| } |
| } |
| } |
| } |
| if (nsrcs != nsrcs0) { |
| inst->setNumSrcs(nsrcs); |
| } |
| switch (nsrcs) { |
| case 0: // convert to TauSafe; |
| return genTauSafe()->getDst(); // TauAnd of nothing is safe |
| |
| case 2: |
| { |
| if (inst->getSrc(0) != inst->getSrc(1)) { |
| break; // don't simplify it |
| } |
| } |
| // fall through and convert to copy; |
| case 1: // convert to copy; |
| return inst->getSrc(0); |
| |
| default: |
| break; |
| } |
| return NULL; |
| } |
| |
| Inst* |
| Simplifier::caseBranch(BranchInst* inst) { |
| bool isTaken; |
| Type::Tag type = inst->getType(); |
| ComparisonModifier mod = inst->getComparisonModifier(); |
| switch (inst->getNumSrcOperands()) { |
| case 1: |
| if(canFoldBranch(type, |
| mod, |
| inst->getSrc(0), |
| isTaken)) { |
| foldBranch(inst, isTaken); |
| return NULL; |
| } |
| else { |
| if(simplifyBranch(type, mod, inst->getTargetLabel(), inst->getSrc(0))) |
| return NULL; |
| } |
| break; |
| case 2: |
| if(canFoldBranch(type, |
| mod, |
| inst->getSrc(0), |
| inst->getSrc(1), |
| isTaken)) { |
| foldBranch(inst, isTaken); |
| return NULL; |
| } |
| else { |
| if(simplifyBranch(type, mod, inst->getTargetLabel(), inst->getSrc(0), inst->getSrc(1))) |
| return NULL; |
| } |
| break; |
| } |
| |
| return inst; |
| } |
| |
| Inst* |
| Simplifier::caseSwitch(SwitchInst* inst) { |
| Opnd* index = inst->getSrc(0); |
| I_32 value; |
| if(ConstantFolder::isConstant(index->getInst(), value)) { |
| foldSwitch(inst, value); |
| return NULL; |
| } else { |
| U_32 numTarget = inst->getNumTargets(); |
| LabelInst** targets = inst->getTargets(); |
| LabelInst* defaultTarget = inst->getDefaultTarget(); |
| if(simplifySwitch(numTarget, targets, defaultTarget, index)) { |
| return NULL; |
| } |
| } |
| return inst; |
| } |
| |
| Inst* |
| Simplifier::caseIndirectCall(CallInst* inst) { |
| Opnd* dst = inst->getDst(); |
| Type* returnType = dst->isNull()? irManager.getTypeManager().getVoidType() : dst->getType(); |
| Opnd** args = inst->getArgs(); |
| U_32 numArgs = inst->getNumArgs(); |
| assert(numArgs >= 2); |
| Opnd* tauNullCheckedFirstArg = args[0]; |
| Opnd* tauTypesChecked = args[1]; |
| Inst* newInst = simplifyIndirectCallInst(inst->getFunPtr(), |
| returnType, |
| tauNullCheckedFirstArg, |
| tauTypesChecked, |
| numArgs-2, // skip taus |
| args+2); |
| if (newInst != NULL) { |
| return newInst; |
| } |
| return inst; |
| } |
| |
| Inst* |
| Simplifier::caseIndirectMemoryCall(CallInst* inst) { |
| Opnd* dst = inst->getDst(); |
| Type* returnType = dst->isNull()? irManager.getTypeManager().getVoidType() : dst->getType(); |
| Opnd** args = inst->getArgs(); |
| U_32 numArgs = inst->getNumArgs(); |
| assert(numArgs >= 2); |
| Opnd* tauNullCheckedFirstArg = args[0]; |
| Opnd* tauTypesChecked = args[1]; |
| Inst* newInst = simplifyIndirectMemoryCallInst(inst->getFunPtr(), |
| returnType, |
| tauNullCheckedFirstArg, |
| tauTypesChecked, |
| numArgs-2, |
| args+2); |
| if (newInst != NULL) { |
| return newInst; |
| } |
| return inst; |
| } |
| |
| Opnd* |
| Simplifier::propagateCopy(Opnd* opnd) { |
| assert(opnd); |
| Inst* inst = opnd->getInst(); |
| if (isCopy(inst)) { |
| return inst->getSrc(0); |
| } |
| return opnd; |
| } |
| |
| //----------------------------------------------------------------------------- |
| // Simplifier methods that generate instructions |
| //----------------------------------------------------------------------------- |
| SimplifierWithInstFactory::SimplifierWithInstFactory(IRManager& irm, |
| bool isLate, |
| Reassociate *reassociate0) |
| : Simplifier(irm, isLate, reassociate0), |
| nextInst(NULL), |
| currentCfgNode(NULL), |
| instFactory(irm.getInstFactory()), |
| opndManager(irm.getOpndManager()), |
| typeManager(irm.getTypeManager()), |
| tauSafeOpnd(NULL), |
| tauMethodSafeOpnd(NULL), |
| tauUnsafeOpnd(NULL) |
| { |
| } |
| |
| void |
| SimplifierWithInstFactory::foldBranch(BranchInst* br, bool isTaken) { |
| FlowGraph::foldBranch(flowGraph, br,isTaken); |
| } |
| |
| void |
| SimplifierWithInstFactory::foldSwitch(SwitchInst* switchInst, U_32 index) { |
| FlowGraph::foldSwitch(flowGraph, switchInst,index); |
| } |
| |
| |
| void |
| SimplifierWithInstFactory::eliminateCheck(Inst* checkInst, bool alwaysThrows) { |
| FlowGraph::eliminateCheck(flowGraph, currentCfgNode,checkInst,alwaysThrows); |
| } |
| |
| U_32 |
| SimplifierWithInstFactory::simplifyControlFlowGraph() { |
| if (Log::isEnabled()) { |
| Log::out() << "Starting simplifyControlFlowGraph" << ::std::endl; |
| } |
| |
| U_32 numInstOptimized = 0; |
| MemoryManager memManager("SimplifierWithInstFactory::simplifyControlFlowGraph"); |
| BitSet* reachableNodes = new (memManager) BitSet(memManager,flowGraph.getMaxNodeId()); |
| BitSet* unreachableInsts = |
| new (memManager) BitSet(memManager,irManager.getInstFactory().getNumInsts()); |
| StlVector<Node*> nodes(memManager); |
| nodes.reserve(flowGraph.getMaxNodeId()); |
| // |
| // Compute postorder list. |
| // |
| flowGraph.getNodesPostOrder(nodes); |
| // Use reverse iterator to generate nodes in reverse postorder. |
| StlVector<Node*>::reverse_iterator niter = nodes.rbegin(); |
| // mark first node as reachable |
| reachableNodes->setBit((*niter)->getId(),true); |
| for (niter = nodes.rbegin(); niter != nodes.rend(); ++niter) { |
| currentCfgNode = *niter; |
| Inst* headInst = (Inst*)currentCfgNode->getFirstInst(); |
| if (reachableNodes->getBit(currentCfgNode->getId()) == false) { |
| // unreachable block |
| // mark block's instructions as unreachable |
| for (Inst* inst = headInst->getNextInst();inst!=NULL;inst=inst->getNextInst()) { |
| unreachableInsts->setBit(inst->getId(),true); |
| } |
| // skip over unreachable block |
| continue; |
| } |
| for (Inst* inst = headInst->getNextInst();inst!=NULL;) { |
| Inst* nextInst = inst->getNextInst(); |
| if (Log::isEnabled()) { |
| Log::out() << "Trying to simplify Instruction: "; |
| inst->print(Log::out()); |
| Log::out() << ::std::endl; |
| } |
| Inst* optimizedInst = optimizeInst(inst); |
| if (optimizedInst != inst) { |
| if (Log::isEnabled()) { |
| Log::out() << "was simplified" << ::std::endl; |
| } |
| // simplification occurred |
| numInstOptimized++; |
| if (optimizedInst != NULL) { |
| if (Log::isEnabled()) { |
| Log::out() << "replacing with new instruction "; |
| optimizedInst->print(Log::out()); |
| Log::out() << ::std::endl; |
| } |
| // instruction was not deleted by optimization |
| // replace with a copy from newInst.dst |
| Opnd* dstOpnd = inst->getDst(); |
| // |
| // some operations, e.g., InitType, don't produce a |
| // value in a destination opnd |
| // |
| if (dstOpnd->isNull() == false) { |
| Opnd* srcOpnd = optimizedInst->getDst(); |
| // |
| // Note, that sometimes dstOpnd could be a null operand |
| // because of instructions that do not define a new |
| // value (e.g., checkelemtype) but are simplified to |
| // instructions that do (e.g., newobj); so we check if |
| // dstOpnd is null first. |
| // |
| Inst* copy = irManager.getInstFactory().makeCopy(dstOpnd, srcOpnd); |
| if (nextInst) { |
| assert(nextInst->getNode()); |
| copy->insertBefore(nextInst); |
| } else { |
| currentCfgNode->appendInst(copy); |
| } |
| if (Log::isEnabled()) { |
| Log::out() << "inserting copy instruction "; |
| copy->print(Log::out()); |
| Log::out() << ::std::endl; |
| } |
| } |
| } |
| inst->unlink(); |
| } |
| inst = nextInst; |
| } |
| // mark successor blocks as reachable |
| Edges::const_iterator |
| i = currentCfgNode->getOutEdges().begin(), |
| iend = currentCfgNode->getOutEdges().end(); |
| for (; i != iend; i++) { |
| Node* succ = (*i)->getTargetNode(); |
| reachableNodes->setBit(succ->getId(),true); |
| } |
| } |
| if (Log::isEnabled()) { |
| Log::out() << "Done simplifyControlFlowGraph" << ::std::endl; |
| } |
| return numInstOptimized; |
| } |
| |
| Inst* |
| SimplifierWithInstFactory::optimizeInst(Inst* inst) { |
| nextInst = inst; |
| return Simplifier::optimizeInst(inst); |
| } |
| |
| void |
| SimplifierWithInstFactory::insertInst(Inst* inst) { |
| inst->insertBefore(nextInst); |
| inst->setBCOffset(nextInst->getBCOffset()); |
| } |
| |
| void |
| SimplifierWithInstFactory::insertInstInHeader(Inst* inst) { |
| 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 |
| if (where!=NULL) { |
| inst->insertBefore(where); |
| } else { |
| head->appendInst(inst); |
| } |
| } |
| |
| Inst* |
| SimplifierWithInstFactory::genAdd(Type* type, Modifier mod, Opnd* src1, Opnd* src2) { |
| Opnd* dst = opndManager.createSsaTmpOpnd(type); |
| Inst* inst = instFactory.makeAdd(mod, dst, src1, src2); |
| insertInst(inst); |
| return inst; |
| } |
| |
| Inst* |
| SimplifierWithInstFactory::genSub(Type* type, Modifier mod, Opnd* src1, Opnd* src2) { |
| Opnd* dst = opndManager.createSsaTmpOpnd(type); |
| Inst* inst = instFactory.makeSub(mod, dst, src1, src2); |
| insertInst(inst); |
| return inst; |
| } |
| |
| Inst* |
| SimplifierWithInstFactory::genNeg(Type* type, Opnd* src) { |
| Opnd* dst = opndManager.createSsaTmpOpnd(type); |
| Inst* inst = instFactory.makeNeg(dst, src); |
| insertInst(inst); |
| return inst; |
| } |
| |
| Inst* |
| SimplifierWithInstFactory::genMul(Type* type, Modifier mod, Opnd* src1, Opnd* src2) { |
| Opnd* dst = opndManager.createSsaTmpOpnd(type); |
| Inst* inst = instFactory.makeMul(mod, dst, src1, src2); |
| insertInst(inst); |
| return inst; |
| } |
| |
| Inst* |
| SimplifierWithInstFactory::genMulHi(Type* type, Modifier mod, Opnd* src1, Opnd* src2) { |
| Opnd* dst = opndManager.createSsaTmpOpnd(type); |
| Inst* inst = instFactory.makeMulHi(mod, dst, src1, src2); |
| insertInst(inst); |
| return inst; |
| } |
| |
| Inst* |
| SimplifierWithInstFactory::genMin(Type* type, Opnd* src1, Opnd* src2) { |
| Opnd* dst = opndManager.createSsaTmpOpnd(type); |
| Inst* inst = instFactory.makeMin(dst, src1, src2); |
| insertInst(inst); |
| return inst; |
| } |
| |
| Inst* |
| SimplifierWithInstFactory::genMax(Type* type, Opnd* src1, Opnd* src2) { |
| Opnd* dst = opndManager.createSsaTmpOpnd(type); |
| Inst* inst = instFactory.makeMax(dst, src1, src2); |
| insertInst(inst); |
| return inst; |
| } |
| |
| Inst* |
| SimplifierWithInstFactory::genAbs(Type* type, Opnd* src1) { |
| Opnd* dst = opndManager.createSsaTmpOpnd(type); |
| Inst* inst = instFactory.makeAbs(dst, src1); |
| insertInst(inst); |
| return inst; |
| } |
| |
| Inst* |
| SimplifierWithInstFactory::genAnd(Type* type, Opnd* src1, Opnd* src2) { |
| Opnd* dst = opndManager.createSsaTmpOpnd(type); |
| Inst* inst = instFactory.makeAnd(dst, src1, src2); |
| insertInst(inst); |
| return inst; |
| } |
| Inst* |
| SimplifierWithInstFactory::genOr(Type* type, Opnd* src1, Opnd* src2) { |
| Opnd* dst = opndManager.createSsaTmpOpnd(type); |
| Inst* inst = instFactory.makeOr(dst, src1, src2); |
| insertInst(inst); |
| return inst; |
| } |
| Inst* |
| SimplifierWithInstFactory::genXor(Type* type, Opnd* src1, Opnd* src2) { |
| Opnd* dst = opndManager.createSsaTmpOpnd(type); |
| Inst* inst = instFactory.makeXor(dst, src1, src2); |
| insertInst(inst); |
| return inst; |
| } |
| Inst* |
| SimplifierWithInstFactory::genNot(Type* type, Opnd* src1) { |
| Opnd* dst = opndManager.createSsaTmpOpnd(type); |
| Inst* inst = instFactory.makeNot(dst, src1); |
| insertInst(inst); |
| return inst; |
| } |
| |
| Inst* |
| SimplifierWithInstFactory::genSelect(Type* type, |
| Opnd* src1, Opnd* src2, Opnd* src3) |
| { |
| Opnd* dst = opndManager.createSsaTmpOpnd(type); |
| Inst* inst = instFactory.makeSelect(dst, src1, src2, src3); |
| insertInst(inst); |
| return inst; |
| } |
| |
| Inst* |
| SimplifierWithInstFactory::genConv(Type* type, Type::Tag toType, |
| Modifier ovfMod, |
| Opnd* src) |
| { |
| Opnd* dst = opndManager.createSsaTmpOpnd(type); |
| Inst* inst = instFactory.makeConv(ovfMod, toType, dst, src); |
| insertInst(inst); |
| return inst; |
| } |
| |
| Inst* |
| SimplifierWithInstFactory::genConvZE(Type* type, Type::Tag toType, |
| Modifier ovfMod, |
| Opnd* src) |
| { |
| Opnd* dst = opndManager.createSsaTmpOpnd(type); |
| Inst* inst = instFactory.makeConvZE(ovfMod, toType, dst, src); |
| insertInst(inst); |
| return inst; |
| } |
| Inst* |
| SimplifierWithInstFactory::genConvUnmanaged(Type* type, Type::Tag toType, |
| Modifier ovfMod, |
| Opnd* src) |
| { |
| Opnd* dst = opndManager.createSsaTmpOpnd(type); |
| Inst* inst = instFactory.makeConvUnmanaged(ovfMod, toType, dst, src); |
| insertInst(inst); |
| return inst; |
| } |
| |
| |
| Inst* |
| SimplifierWithInstFactory::genShladd(Type* type, |
| Opnd* value, Opnd* shiftAmount, |
| Opnd* addTo) |
| { |
| OpndManager &opndManager = irManager.getOpndManager(); |
| Opnd* dst = opndManager.createSsaTmpOpnd(type); |
| Inst* inst = instFactory.makeShladd(dst, value, shiftAmount, addTo); |
| insertInst(inst); |
| return inst; |
| } |
| Inst* |
| SimplifierWithInstFactory::genShl(Type* type, |
| Modifier smmod, |
| Opnd* src1, Opnd* src2) { |
| Opnd* dst = opndManager.createSsaTmpOpnd(type); |
| Inst* inst = instFactory.makeShl(smmod, dst, src1, src2); |
| insertInst(inst); |
| return inst; |
| } |
| Inst* |
| SimplifierWithInstFactory::genShr(Type* type, Modifier mods, |
| Opnd* src1, Opnd* src2) { |
| Opnd* dst = opndManager.createSsaTmpOpnd(type); |
| Inst* inst = instFactory.makeShr(mods, dst, src1, src2); |
| insertInst(inst); |
| return inst; |
| } |
| Inst* |
| SimplifierWithInstFactory::genCmp(Type* type, Type::Tag insttype, |
| ComparisonModifier mod, |
| Opnd* src1, Opnd* src2) |
| { |
| Opnd* dst = opndManager.createSsaTmpOpnd(type); |
| Inst* inst = instFactory.makeCmp(mod, insttype, dst, src1, src2); |
| insertInst(inst); |
| return inst; |
| } |
| void |
| SimplifierWithInstFactory::genBranch(Type::Tag insttype, |
| ComparisonModifier mod, |
| LabelInst* label, |
| Opnd* src1, Opnd* src2) |
| { |
| Inst* inst = instFactory.makeBranch(mod, insttype, src1, src2, label); |
| insertInst(inst); |
| } |
| |
| void |
| SimplifierWithInstFactory::genJump(LabelInst* label) |
| { |
| Inst* inst = instFactory.makeJump(label); |
| insertInst(inst); |
| } |
| |
| void |
| SimplifierWithInstFactory::genBranch(Type::Tag insttype, |
| ComparisonModifier mod, |
| LabelInst* label, |
| Opnd* src1) |
| { |
| Inst* inst = instFactory.makeBranch(mod, insttype, src1, label); |
| insertInst(inst); |
| } |
| |
| Inst* |
| SimplifierWithInstFactory::genDirectCall( |
| MethodDesc* methodDesc, |
| Type* returnType, |
| Opnd* tauNullCheckedFirstArg, |
| Opnd* tauTypesChecked, |
| U_32 numArgs, |
| Opnd* args[]) |
| { |
| Opnd* dst; |
| if (returnType->tag == Type::Void) { |
| dst = OpndManager::getNullOpnd(); |
| } else { |
| dst = opndManager.createSsaTmpOpnd(returnType); |
| } |
| Inst* inst = instFactory.makeDirectCall(dst, |
| tauNullCheckedFirstArg, tauTypesChecked, |
| numArgs, args, |
| methodDesc); |
| insertInst(inst); |
| return inst; |
| } |
| Inst* |
| SimplifierWithInstFactory::genLdConstant(I_32 val) { |
| Opnd* dst = opndManager.createSsaTmpOpnd(typeManager.getInt32Type()); |
| Inst* inst = instFactory.makeLdConst(dst, val); |
| insertInst(inst); |
| return inst; |
| } |
| Inst* |
| SimplifierWithInstFactory::genLdConstant(int64 val) { |
| Opnd* dst = opndManager.createSsaTmpOpnd(typeManager.getInt64Type()); |
| Inst* inst = instFactory.makeLdConst(dst, val); |
| insertInst(inst); |
| return inst; |
| } |
| Inst* |
| SimplifierWithInstFactory::genLdConstant(float val) { |
| Opnd* dst = opndManager.createSsaTmpOpnd(typeManager.getSingleType()); |
| Inst* inst = instFactory.makeLdConst(dst, val); |
| insertInst(inst); |
| return inst; |
| } |
| Inst* |
| SimplifierWithInstFactory::genLdConstant(double val) { |
| Opnd* dst = opndManager.createSsaTmpOpnd(typeManager.getDoubleType()); |
| Inst* inst = instFactory.makeLdConst(dst, val); |
| insertInst(inst); |
| return inst; |
| } |
| |
| Inst* |
| SimplifierWithInstFactory::genLdConstant(Type* type, ConstInst::ConstValue val) { |
| Opnd* dst = opndManager.createSsaTmpOpnd(type); |
| Inst* inst = instFactory.makeLdConst(dst, val); |
| insertInst(inst); |
| return inst; |
| } |
| |
| Inst* |
| SimplifierWithInstFactory::genTauLdInd(Modifier mod, Type* type, Type::Tag ldType, |
| Opnd* ptr, Opnd *tauNonNullBase, |
| Opnd *tauAddressInRange) |
| { |
| Opnd* dst = opndManager.createSsaTmpOpnd(type); |
| Inst* inst = instFactory.makeTauLdInd(mod, ldType, dst, ptr, tauNonNullBase, |
| tauAddressInRange); |
| insertInst(inst); |
| return inst; |
| } |
| |
| Inst* |
| SimplifierWithInstFactory::genLdRef(Modifier mod, Type* type, |
| U_32 token, |
| MethodDesc *methodDesc) |
| { |
| Opnd* dst = opndManager.createSsaTmpOpnd(type); |
| Inst* inst = instFactory.makeLdRef(mod, dst, methodDesc, token); |
| insertInst(inst); |
| return inst; |
| } |
| |
| Inst* |
| SimplifierWithInstFactory::genLdFunAddrSlot(MethodDesc* methodDesc) { |
| Opnd* dst = opndManager.createSsaTmpOpnd(typeManager.getMethodPtrType(methodDesc)); |
| Inst* inst = instFactory.makeLdFunAddrSlot(dst, methodDesc); |
| insertInst(inst); |
| return inst; |
| } |
| |
| Inst* |
| SimplifierWithInstFactory::genGetVTableAddr(ObjectType* type) { |
| Opnd* dst = opndManager.createSsaTmpOpnd(typeManager.getVTablePtrType(type)); |
| Inst* inst = instFactory.makeGetVTableAddr(dst, type); |
| insertInst(inst); |
| return inst; |
| } |
| |
| Inst* |
| SimplifierWithInstFactory::genCompressRef(Opnd* uncompref) |
| { |
| Type* uncompRefType = uncompref->getType(); |
| Type* compRefType = typeManager.compressType(uncompRefType); |
| Opnd* dst = opndManager.createSsaTmpOpnd(compRefType); |
| Inst* inst = instFactory.makeCompressRef(dst, uncompref); |
| insertInst(inst); |
| return inst; |
| } |
| |
| Inst* |
| SimplifierWithInstFactory::genUncompressRef(Opnd* compref) |
| { |
| Type* compRefType = compref->getType(); |
| Type* uncompRefType = typeManager.uncompressType(compRefType); |
| Opnd* dst = opndManager.createSsaTmpOpnd(uncompRefType); |
| Inst* inst = instFactory.makeUncompressRef(dst, compref); |
| insertInst(inst); |
| return inst; |
| } |
| |
| |
| Inst* |
| SimplifierWithInstFactory::genLdFieldOffsetPlusHeapbase(FieldDesc* fd) { |
| Opnd* dst = opndManager.createSsaTmpOpnd(typeManager.getOffsetPlusHeapbaseType()); |
| Inst* inst = instFactory.makeLdFieldOffsetPlusHeapbase(dst, fd); |
| insertInst(inst); |
| return inst; |
| } |
| |
| Inst* |
| SimplifierWithInstFactory::genLdArrayBaseOffsetPlusHeapbase(Type* elemType) { |
| Opnd* dst = opndManager.createSsaTmpOpnd(typeManager.getOffsetPlusHeapbaseType()); |
| Inst* inst = instFactory.makeLdArrayBaseOffsetPlusHeapbase(dst, elemType); |
| insertInst(inst); |
| return inst; |
| } |
| |
| Inst* |
| SimplifierWithInstFactory::genLdArrayLenOffsetPlusHeapbase(Type* elemType) { |
| Opnd* dst = opndManager.createSsaTmpOpnd(typeManager.getOffsetPlusHeapbaseType()); |
| Inst* inst = instFactory.makeLdArrayLenOffsetPlusHeapbase(dst, elemType); |
| insertInst(inst); |
| return inst; |
| } |
| |
| Inst* |
| SimplifierWithInstFactory::genAddOffsetPlusHeapbase(Type *ptrType, |
| Opnd *compRef, |
| Opnd *offsetPlusHeapbase) { |
| Opnd* dst = opndManager.createSsaTmpOpnd(ptrType); |
| Inst* inst = instFactory.makeAddOffsetPlusHeapbase(dst, compRef, |
| offsetPlusHeapbase); |
| insertInst(inst); |
| return inst; |
| } |
| |
| Inst* |
| SimplifierWithInstFactory::genTauSafe() { |
| if (tauSafeOpnd) { |
| return tauSafeOpnd->getInst(); |
| } |
| Opnd* dst = opndManager.createSsaTmpOpnd(typeManager.getTauType()); |
| Inst* inst = instFactory.makeTauSafe(dst); |
| insertInstInHeader(inst); |
| tauSafeOpnd = dst; |
| return inst; |
| } |
| |
| Inst* |
| SimplifierWithInstFactory::genTauMethodSafe() { |
| if (tauMethodSafeOpnd) { |
| return tauMethodSafeOpnd->getInst(); |
| } |
| Opnd* dst = opndManager.createSsaTmpOpnd(typeManager.getTauType()); |
| Inst* inst = instFactory.makeTauPoint(dst); |
| insertInstInHeader(inst); |
| tauMethodSafeOpnd = dst; |
| return inst; |
| } |
| |
| Inst* |
| SimplifierWithInstFactory::genTauUnsafe() { |
| if (tauUnsafeOpnd) { |
| return tauUnsafeOpnd->getInst(); |
| } |
| Opnd* dst = opndManager.createSsaTmpOpnd(typeManager.getTauType()); |
| Inst* inst = instFactory.makeTauUnsafe(dst); |
| insertInstInHeader(inst); |
| tauUnsafeOpnd = dst; |
| return inst; |
| } |
| |
| Inst* |
| SimplifierWithInstFactory::genTauStaticCast(Opnd *src, Opnd *tauCheckedCast, Type *castType) |
| { |
| Opnd* dst = opndManager.createSsaTmpOpnd(castType); |
| Inst* inst = instFactory.makeTauStaticCast(dst, src, tauCheckedCast, castType); |
| insertInst(inst); |
| return inst; |
| } |
| |
| Inst* |
| SimplifierWithInstFactory::genTauHasType(Opnd *src, Type *castType) |
| { |
| Opnd* dst = opndManager.createSsaTmpOpnd(typeManager.getTauType()); |
| Inst* inst = instFactory.makeTauHasType(dst, src, castType); |
| insertInst(inst); |
| return inst; |
| } |
| |
| Inst* |
| SimplifierWithInstFactory::genTauHasExactType(Opnd *src, Type *castType) |
| { |
| Opnd* dst = opndManager.createSsaTmpOpnd(typeManager.getTauType()); |
| Inst* inst = instFactory.makeTauHasExactType(dst, src, castType); |
| insertInst(inst); |
| return inst; |
| } |
| |
| |
| Inst* |
| SimplifierWithInstFactory::genTauIsNonNull(Opnd *src) |
| { |
| Opnd* dst = opndManager.createSsaTmpOpnd(typeManager.getTauType()); |
| Inst* inst = instFactory.makeTauIsNonNull(dst, src); |
| insertInst(inst); |
| return inst; |
| } |
| |
| |
| Opnd* |
| Simplifier::simplifyTauCheckCast(Opnd* src, Opnd* tauCheckedNull, Type* castType, |
| bool &alwaysThrows) |
| { |
| Type *opndType = src->getType(); |
| if (isNullObject(src)) { |
| return genTauSafe()->getDst(); |
| } else if (opndType->isUnresolvedType()) { |
| return NULL; |
| } else if (irManager.getTypeManager().isResolvedAndSubClassOf(opndType, castType)) { |
| return genTauHasType(src, castType)->getDst(); |
| } else if (!irManager.getTypeManager().isResolvedAndSubClassOf(castType, opndType)) { |
| if (Log::isEnabled()) { |
| Log::out() << "in simplifyTauCheckCast: castToType "; |
| castType->print(Log::out()); |
| Log::out() << " not subtype of source "; |
| src->print(Log::out()); |
| Log::out() << " type "; |
| opndType->print(Log::out()); |
| Log::out() << ::std::endl; |
| } |
| return NULL; |
| } |
| return NULL; |
| } |
| |
| Opnd* |
| Simplifier::simplifyTauHasType(Opnd* src, Type* castType) |
| { |
| // all references have type java/lang/Object |
| if ((castType == irManager.getTypeManager().getSystemObjectType()) || |
| (castType == irManager.getTypeManager().getCompressedSystemObjectType())) { |
| return genTauSafe()->getDst(); |
| } |
| // otherwise, check for constants or casts |
| #ifndef NDEBUG |
| Type *opndType = src->getType(); |
| #endif |
| Inst *srcInst = src->getInst(); |
| Opcode opc = srcInst->getOpcode(); |
| switch (opc) { |
| case Op_NewObj: |
| case Op_NewArray: |
| case Op_NewMultiArray: |
| case Op_TauLdInd: |
| case Op_TauLdField: |
| case Op_TauLdElem: |
| case Op_LdStatic: |
| case Op_LdConstant: // must be ldNull; we have no other object constants |
| return genTauSafe()->getDst(); |
| case Op_TauStaticCast: |
| { |
| TypeInst *staticCastInst = srcInst->asTypeInst(); |
| Type *typeInfo = staticCastInst->getTypeInfo(); |
| assert(typeInfo == opndType); |
| Opnd *tauCastChecked = staticCastInst->getSrc(1); |
| |
| // if we have an exact type match, use src |
| if (typeInfo == castType) { |
| return tauCastChecked; |
| } |
| // otherwise, first check whether we can be more precise than this cast |
| DeadCodeEliminator::copyPropagate(staticCastInst); |
| Opnd *staticCastSrc = staticCastInst->getSrc(0); |
| tauCastChecked = staticCastInst->getSrc(1); |
| |
| Opnd *foundRecurse = simplifyTauHasType(staticCastSrc, castType); |
| if (foundRecurse) { |
| return foundRecurse; |
| } |
| // couldn't be more precise, just use this one. |
| if (irManager.getTypeManager().isResolvedAndSubClassOf(typeInfo, castType)) { |
| return tauCastChecked; |
| } |
| } |
| break; |
| case Op_Copy: |
| assert(0); // should have been copy-propagated |
| case Op_LdVar: |
| default: |
| break; |
| } |
| return NULL; |
| } |
| |
| Opnd* |
| Simplifier::simplifyTauHasExactType(Opnd* src, Type* castType) |
| { |
| Inst *srcInst = src->getInst(); |
| Opcode opc = srcInst->getOpcode(); |
| if ((opc == Op_NewObj) || (opc == Op_NewArray) || (opc == Op_NewMultiArray)) { |
| return genTauSafe()->getDst(); |
| } |
| return NULL; |
| } |
| |
| Opnd* |
| Simplifier::simplifyTauIsNonNull(Opnd* src) |
| { |
| Inst *srcInst = src->getInst(); |
| Opcode opc = srcInst->getOpcode(); |
| if ((opc == Op_NewObj) || (opc == Op_NewArray) || (opc == Op_NewMultiArray)) { |
| return genTauSafe()->getDst(); |
| } |
| return NULL; |
| } |
| |
| Opnd* |
| Simplifier::simplifyTauStaticCast(Opnd *src, Opnd *tauCheckedCast, Type *castType) |
| { |
| return NULL; |
| } |
| |
| |
| void |
| SimplifierWithInstFactory::genThrowSystemException(CompilationInterface::SystemExceptionId exceptionId) |
| { |
| Inst* inst = instFactory.makeThrowSystemException(exceptionId); |
| insertInst(inst); |
| } |
| |
| |
| static Class_Handle getClassHandle(Opnd* opnd) { |
| //class handle can be: unmanaged ptr (from magics) or pointer_size_int const (I_32 or int64) if loaded as a const |
| //assert(opnd->getType()->isUnmanagedPtr() || opnd->getType()->isInt4() || opnd->getType()->isInt8()); |
| assert(opnd->getType()->isUnmanagedPtr()); |
| Inst* inst = opnd->getInst(); |
| Class_Handle ch = NULL; |
| if (inst->asConstInst() != NULL) { |
| ch = (Class_Handle)(POINTER_SIZE_INT)inst->asConstInst()->getValue().i8; |
| } |
| return ch; |
| } |
| |
| Inst* Simplifier::simplifyJitHelperCall(JitHelperCallInst* inst) { |
| Inst* res = inst; |
| Class_Handle ch = NULL; |
| TypeManager& tm = irManager.getTypeManager(); |
| switch(inst->getJitHelperId()) { |
| case ClassIsArray: |
| ch = getClassHandle(inst->getSrc(0)); |
| if (ch) { |
| res = genLdConstant((I_32)VMInterface::isArrayType(ch)); |
| } |
| break; |
| case ClassGetAllocationHandle: |
| ch = getClassHandle(inst->getSrc(0)); |
| if (ch) { |
| ConstInst::ConstValue v; |
| v.i8 = (POINTER_SIZE_SINT)VMInterface::getAllocationHandle(ch); |
| res = genLdConstant(tm.getInt32Type(), v); |
| assert((sizeof(void*) == 4) && "TODO fix allocation helper on 64 bit"); |
| } |
| break; |
| case ClassGetTypeSize: |
| ch = getClassHandle(inst->getSrc(0)); |
| if (ch) { |
| res = genLdConstant((I_32)VMInterface::getObjectSize(ch)); |
| } |
| break; |
| case ClassGetArrayElemSize: |
| ch = getClassHandle(inst->getSrc(0)); |
| if (ch) { |
| res = genLdConstant((I_32)VMInterface::getArrayElemSize(ch)); |
| } |
| break; |
| case ClassIsInterface: |
| ch = getClassHandle(inst->getSrc(0)); |
| if (ch) { |
| res = genLdConstant((I_32)VMInterface::isInterfaceType(ch)); |
| } |
| break; |
| case ClassIsFinal: |
| ch = getClassHandle(inst->getSrc(0)); |
| if (ch) { |
| res = genLdConstant((I_32)VMInterface::isFinalType(ch)); |
| } |
| break; |
| case ClassGetArrayClass: |
| ch = getClassHandle(inst->getSrc(0)); |
| if (ch) { |
| ConstInst::ConstValue v; |
| v.i8 = (POINTER_SIZE_SINT)VMInterface::getArrayVMTypeHandle(ch, false); |
| res = genLdConstant(tm.getUnmanagedPtrType(tm.getInt8Type()), v); |
| } |
| break; |
| case ClassIsFinalizable: |
| ch = getClassHandle(inst->getSrc(0)); |
| if (ch) { |
| res = genLdConstant((I_32)VMInterface::isFinalizable(ch)); |
| } |
| break; |
| case ClassGetFastCheckDepth: |
| ch = getClassHandle(inst->getSrc(0)); |
| if (ch) { |
| int depth = 0; |
| if (VMInterface::getClassFastInstanceOfFlag(ch)) { |
| depth = (I_32)VMInterface::getClassDepth(ch); |
| } |
| res = genLdConstant(depth); |
| } |
| break; |
| default: break; |
| } |
| return res; |
| } |
| |
| } //namespace Jitrino |