in vm/jitrino/src/optimizer/constantfolder.cpp [544:990]
bool ConstantFolder::foldConv(Type::Tag fromType, Type::Tag toType, Modifier mod,
ConstInst::ConstValue src,
ConstInst::ConstValue& res)
{
bool ovfm = (mod.getOverflowModifier()!=Overflow_None);
switch (toType) {
case Type::Int32:
#ifndef PONTER64
case Type::IntPtr:
#endif
if (Type::isInteger(fromType)) {
if (Type::isIntegerOf4Signed(fromType)) {
res.i4 = src.i4; return true;
} else if (Type::isIntegerOf4Unsigned(fromType)) {
res.i4 = src.i4;
if (ovfm && (src.i4 < 0)) return false;
return true;
} else if (Type::isIntegerOf8Signed(fromType)) {
res.i4 = CAST(I_32, src.i8);
if (ovfm && (src.i8 != CAST(int64, res.i4))) return false;
return true;
} else if (Type::isIntegerOf8Unsigned(fromType)) {
res.i4 = CAST(I_32, CAST(uint64, src.i8));
if (ovfm && (CAST(uint64, src.i8) != CAST(uint64, res.i4))) return false;
return true;
}
assert(0);
} else if (fromType == Type::Single) {
res.i4 = float2int<I_32, float>(src.s);
if (ovfm && (src.s != CAST(float, res.i4))) return false;
return true;
} else if (fromType == Type::Double) {
res.i4 = float2int<I_32, double>(src.d);
if (ovfm && (src.d != CAST(double, res.i4))) return false;
return true;
}
break;
case Type::UInt32:
#ifndef PONTER64
case Type::UIntPtr:
#endif
if (Type::isInteger(fromType)) {
if (Type::isIntegerOf4Bytes(fromType)) {
res.i4 = src.i4; return true;
} else if (Type::isIntegerOf8Signed(fromType)) {
res.i4 = CAST(I_32, CAST(U_32, src.i8));
if (ovfm && (src.i8 != CAST(int64, CAST(U_32, res.i4)))) return false;
return true;
} else if (Type::isIntegerOf8Unsigned(fromType)) {
res.i4 = CAST(I_32, CAST(U_32, CAST(uint64, src.i8)));
if (ovfm && (CAST(uint64, src.i8) != CAST(uint64, CAST(U_32, res.i4)))) return false;
return true;
}
assert(0);
} else if (fromType == Type::Single) {
res.i4 = float2uint<U_32, float>(src.s);
if (ovfm && (src.s != CAST(float, CAST(U_32, res.i4)))) return false;
return true;
} else if (fromType == Type::Double) {
res.i4 = float2uint<U_32, double>(src.d);
if (ovfm && (src.d != CAST(double, CAST(U_32, res.i4)))) return false;
return true;
}
break;
case Type::Int64:
#ifdef PONTER64
case Type::IntPtr:
#endif
assert(!ovfm || mod.getOverflowModifier()==Overflow_Signed);
if (Type::isInteger(fromType)) {
if (Type::isIntegerOf4Signed(fromType)) {
res.i8 = src.i4; return true;
} else if (Type::isIntegerOf4Unsigned(fromType)) {
res.i8 = CAST(U_32, src.i4);
if (ovfm && (src.i4 < 0)) return false;
return true;
} else if (Type::isIntegerOf8Signed(fromType)) {
res.i8 = src.i8; return true;
} else if (Type::isIntegerOf8Unsigned(fromType)) {
res.i8 = src.i8;
if (ovfm && (src.i8 < 0)) return false;
return true;
}
assert(0);
} else if (fromType == Type::Single) {
res.i8 = float2int<int64, float>(src.s);
if (ovfm && (src.s != CAST(float, res.i8))) return false;
return true;
} else if (fromType == Type::Double) {
res.i8 = float2int<int64, double>(src.d);
if (ovfm && (src.d != CAST(double, res.i8))) return false;
return true;
}
break;
case Type::UInt64:
#ifdef PONTER64
case Type::UIntPtr:
#endif
assert(!ovfm || mod.getOverflowModifier()==Overflow_Unsigned);
if (Type::isInteger(fromType)) {
if (Type::isIntegerOf4Signed(fromType)) {
res.i8 = CAST(uint64, CAST(U_32, src.i4));
if (ovfm && (src.i4 < 0)) return false;
return true;
} else if (Type::isIntegerOf4Unsigned(fromType)) {
res.i8 = CAST(uint64, CAST(U_32, src.i4)); return true;
} else if (Type::isIntegerOf8Bytes(fromType)) {
res.i8 = src.i8; return true;
}
} else if (fromType == Type::Single) {
res.i8 = float2uint<uint64, float>(src.s);
if (ovfm) return false;
return true;
} else if (fromType == Type::Double) {
return false;
}
break;
case Type::Single:
switch (fromType) {
case Type::Int32:
res.s = CAST(float, src.i4); return true;
case Type::UInt32:
res.s = CAST(float, CAST(U_32, src.i4)); return true;
case Type::Int64:
res.s = CAST(float, src.i8);
if (ovfm && (src.i8 != float2int<int64, float>(res.s))) return false;
return true;
case Type::UInt64:
return false;
case Type::Single:
res.s = src.s; return true;
case Type::Double:
res.s = CAST(float, src.d);
if (ovfm && (src.d != CAST(double, res.s))) return false;
return true;
case Type::Float:
default:
break;
}
break;
case Type::Double:
switch (fromType) {
case Type::Int32:
res.d = CAST(double, src.i4); return true;
case Type::UInt32:
res.d = CAST(double, CAST(U_32, src.i4)); return true;
case Type::Int64:
res.d = CAST(double, src.i8); return true;
case Type::UInt64:
return false;
case Type::Single:
res.d = CAST(double, src.s); return true;
case Type::Double:
res.d = src.d; return true;
case Type::Float:
default:
break;
}
break;
case Type::UnmanagedPtr:
// Let's accept the conversion from properly sized integer
#ifdef PONTER64
if (Type::isIntegerOf8Bytes(fromType)) {
#else
if (Type::isIntegerOf4Bytes(fromType)) {
#endif
return true;
}
break;
default:
break;
}
return false;
}
bool
ConstantFolder::foldCmp32(ComparisonModifier mod, I_32 c1, I_32 c2, I_32& result) {
switch (mod) {
case Cmp_EQ: result = ((c1 == c2)?1:0); return true;
case Cmp_NE_Un: result = ((c1 != c2)?1:0); return true;
case Cmp_GT: result = ((c1 > c2)?1:0); return true;
case Cmp_GT_Un: result = ((CAST(U_32, c1) > CAST(U_32, c2))?1:0); return true;
case Cmp_GTE: result = ((c1 >= c2)?1:0); return true;
case Cmp_GTE_Un:result = ((CAST(U_32, c1) >= CAST(U_32, c2))?1:0); return true;
default: break;
}
return false;
}
bool
ConstantFolder::foldCmpRef(ComparisonModifier mod, void* c1, void* c2, I_32& result) {
switch (mod) {
case Cmp_EQ: result = ((c1 == c2)?1:0); return true;
case Cmp_NE_Un: result = ((c1 != c2)?1:0); return true;
case Cmp_GT: result = ((c1 > c2)?1:0); return true;
case Cmp_GT_Un: result = ((c1 > c2)?1:0); return true;
case Cmp_GTE: result = ((c1 >= c2)?1:0); return true;
case Cmp_GTE_Un:result = ((c1 >= c2)?1:0); return true;
default: break;
}
return false;
}
bool
ConstantFolder::foldCmp64(ComparisonModifier mod, int64 c1, int64 c2, I_32& result) {
switch (mod) {
case Cmp_EQ: result = ((c1 == c2)?1:0); return true;
case Cmp_NE_Un: result = ((c1 != c2)?1:0); return true;
case Cmp_GT: result = ((c1 > c2)?1:0); return true;
case Cmp_GT_Un: result = ((CAST(uint64, c1) > CAST(uint64, c2))?1:0); return true;
case Cmp_GTE: result = ((c1 >= c2)?1:0); return true;
case Cmp_GTE_Un:result = ((CAST(uint64, c1) >= CAST(uint64, c2))?1:0); return true;
default: break;
}
return false;
}
bool
ConstantFolder::foldCmpSingle(ComparisonModifier mod, float c1, float c2, I_32& result) {
switch (mod) {
case Cmp_EQ:
if (isnan(c1) || isnan(c2)) { result = false; }
else { result = ((c1 == c2)?1:0); }
return true;
case Cmp_NE_Un:
if (isnan(c1) || isnan(c2)) { result = true; }
else { result = ((c1 != c2)?1:0); }
return true;
case Cmp_GT:
case Cmp_GT_Un:
if (isnan(c1) || isnan(c2)) { result = (mod == Cmp_GT_Un); }
else { result = ((c1 > c2)?1:0); }
return true;
case Cmp_GTE:
case Cmp_GTE_Un:
if (isnan(c1) || isnan(c2)) { result = (mod == Cmp_GTE_Un); }
else { result = ((c1 >= c2)?1:0); }
return true;
default: break;
}
return false;
}
bool
ConstantFolder::foldCmpDouble(ComparisonModifier mod, double c1, double c2, I_32& result){
switch (mod) {
case Cmp_EQ:
if (isnan(c1) || isnan(c2)) { result = false; }
else { result = ((c1 == c2)?1:0); }
return true;
case Cmp_NE_Un:
if (isnan(c1) || isnan(c2)) { result = true; }
else { result = ((c1 != c2)?1:0); }
return true;
case Cmp_GT:
case Cmp_GT_Un:
if (isnan(c1) || isnan(c2)) { result = (mod == Cmp_GT_Un); }
else { result = ((c1 > c2)?1:0); }
return true;
case Cmp_GTE:
case Cmp_GTE_Un:
if (isnan(c1) || isnan(c2)) { result = (mod == Cmp_GTE_Un); }
else { result = ((c1 >= c2)?1:0); }
return true;
default: break;
}
return false;
}
bool
ConstantFolder::foldCmp32(ComparisonModifier mod, I_32 c, I_32& result) {
switch (mod) {
case Cmp_Zero: result = ((c == 0)?1:0); return true;
case Cmp_NonZero: result = ((c != 0)?1:0); return true;
default: break;
}
return false;
}
bool
ConstantFolder::foldCmp64(ComparisonModifier mod, int64 c, I_32& result) {
switch (mod) {
case Cmp_Zero: result = ((c == 0)?1:0); return true;
case Cmp_NonZero: result = ((c != 0)?1:0); return true;
default: break;
}
return false;
}
bool
ConstantFolder::foldCmpRef(ComparisonModifier mod, void* c, I_32& result) {
switch (mod) {
case Cmp_Zero: result = ((c == NULL)?1:0); return true;
case Cmp_NonZero: result = ((c != NULL)?1:0); return true;
default: break;
}
return false;
}
bool
ConstantFolder::foldCmp(Type::Tag cmpTypeTag,
ComparisonModifier mod,
ConstInst::ConstValue val,
ConstInst::ConstValue& result) {
switch (cmpTypeTag) {
case Type::Int32: return foldCmp32(mod, val.i4, result.i4);
case Type::Int64: return foldCmp64(mod, val.i8, result.i4);
case Type::UInt32: return foldCmp32(mod, val.i4, result.i4);
case Type::UInt64: return foldCmp64(mod, val.i8, result.i4);
default: break;
}
// fold comparisons of references against null
if (Type::isObject(cmpTypeTag))
return foldCmpRef(mod, val.i, result.i4);
return false;
}
//
// binary comparison
//
bool
ConstantFolder::foldCmp(Type::Tag cmpTypeTag,
ComparisonModifier mod,
ConstInst::ConstValue val1,
ConstInst::ConstValue val2,
ConstInst::ConstValue& result) {
switch (cmpTypeTag) {
case Type::Int32: case Type::UInt32: return foldCmp32(mod, val1.i4, val2.i4, result.i4);
case Type::Int64: case Type::UInt64: return foldCmp64(mod, val1.i8, val2.i8, result.i4);
case Type::Single: return foldCmpSingle(mod, val1.s, val2.s, result.i4);
case Type::Double: return foldCmpDouble(mod, val1.d, val2.d, result.i4);
default: break;
}
return false;
}
bool
ConstantFolder::foldConstant(Type::Tag type,
Opcode opc,
ConstInst::ConstValue val1,
ConstInst::ConstValue val2,
ConstInst::ConstValue& result,
bool is_signed) {
switch (type) {
case Type::Int8:
case Type::UInt8: return fold8(opc, (I_8)val1.i4, (I_8)val2.i4, result.i4, is_signed);
case Type::Int16:
case Type::UInt16: return fold16(opc, (int16)val1.i4, (int16)val2.i4, result.i4, is_signed);
case Type::Int32:
case Type::UInt32: return fold32(opc, val1.i4, val2.i4, result.i4, is_signed);
case Type::Int64:
case Type::UInt64: return fold64(opc, val1.i8, val2.i8, result.i8, is_signed);
case Type::IntPtr:
case Type::UIntPtr: {
int psi = sizeof(POINTER_SIZE_INT);
switch (psi) {
case 1: return fold8(opc, (I_8)val1.i4, (I_8)val2.i4, result.i4, is_signed);
case 2: return fold16(opc, (int16)val1.i4, (int16)val2.i4, result.i4, is_signed);
case 4: return fold32(opc, val1.i4, val2.i4, result.i4, is_signed);
case 8: return fold64(opc, val1.i8, val2.i8, result.i8, is_signed);
default: return false;
}
}
case Type::Single: return foldSingle(opc, val1.s, val2.s, result.s);
case Type::Double: return foldDouble(opc, val1.d, val2.d, result.d);
default: return false;
}
}
bool
ConstantFolder::foldConstant(Type::Tag type,
Opcode opc,
ConstInst::ConstValue val,
ConstInst::ConstValue& result) {
switch (type) {
case Type::Int32:
case Type::UInt32:
return fold32(opc, val.i4, result.i4);
case Type::Int64:
case Type::UInt64:
return fold64(opc, val.i8, result.i8);
case Type::Single:
return foldSingle(opc, val.s, result.s);
case Type::Double:
return foldDouble(opc, val.d, result.d);
default: break;
}
return false;
}
//
// unary comparison
//
//
// Tries to constant fold the instruction, setting the resulting constant
// value to result. Returns true if instruction was folded.
//
bool
ConstantFolder::fold(Inst* inst, ConstInst::ConstValue& result) {
U_32 numSrcs = inst->getNumSrcOperands();
if (numSrcs == 0)
return false;
ConstInst* constSrc0 = inst->getSrc(0)->getInst()->asConstInst();
if (constSrc0 == NULL)
return false;
Opcode opc = inst->getOpcode();
if (numSrcs == 1) {
if (opc == Op_Cmp) {
return foldCmp(constSrc0->getType(),
inst->getComparisonModifier(),
constSrc0->getValue(),
result);
}
Modifier mod = inst->getModifier();
return foldConstant(inst->getType(),
inst->getOpcode(),
constSrc0->getValue(),
result);
}
ConstInst* constSrc1 = inst->getSrc(1)->getInst()->asConstInst();
if (constSrc1 == NULL)
return false;
if (numSrcs == 2) {
if (opc == Op_Cmp) {
assert(constSrc0->getType() == constSrc1->getType());
return foldCmp(inst->getType(),
inst->getComparisonModifier(),
constSrc0->getValue(),
constSrc1->getValue(),
result);
}
Modifier mod = inst->getModifier();
bool is_signed = mod.isSigned();
return foldConstant(inst->getType(),
inst->getOpcode(),
constSrc0->getValue(),
constSrc1->getValue(),
result,
is_signed);
}
return false;
}
} //namespace Jitrino