blob: 89da5867b163fc4ea4f6a8ef03a3c74d23c41df0 [file] [log] [blame]
/*
* 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