Split Conv<T> into type specialized ConvToArr, ConvToBool, ConvToDbl, ConvToInt, ConvToObj and ConvToStr instructions.
This is a "mechanical" refactoring that is not supposed to introduce any new behavior or to fix anything. It sets the stage for further changes that will reduce the number of places where code generation punts.
Esse commit está contido em:
@@ -375,11 +375,17 @@ D:Int = OpMul S0:{Int|Bool} S1:{Int|Bool}
|
||||
Integer/boolean arithmetic. Performs the operation described by the
|
||||
opcode name on S0 and S1, and puts the result in D.
|
||||
|
||||
|
||||
3. Type conversions
|
||||
|
||||
D:T = Conv<T> S0:Gen
|
||||
D:Arr = ConvToArr S0:Gen
|
||||
D:Bool = ConvToBool S0:Gen
|
||||
D:Dbl = ConvToDbl S0:Gen
|
||||
D:Int = ConvToInt S0:Gen
|
||||
D:Obj = ConvoObj S0:Gen
|
||||
D:Str = ConvToStr S0:Gen
|
||||
|
||||
Convert S0 from its current type to type T, according to the PHP
|
||||
Convert S0 from its current type to destination type, according to the PHP
|
||||
semantics of such a conversion.
|
||||
|
||||
|
||||
|
||||
@@ -1588,7 +1588,6 @@ asm_label(a, falseLabel);
|
||||
asm_label(a, out);
|
||||
}
|
||||
|
||||
HOT_FUNC_VM
|
||||
ArrayData* new_singleton_array_helper(TypedValue value) {
|
||||
// tvCastToArrayInPlace overwrites value and thus decrements the ref count
|
||||
// of any counted object that value refers to.
|
||||
@@ -1602,8 +1601,17 @@ ArrayData* new_singleton_array_helper(TypedValue value) {
|
||||
return value.m_data.parr;
|
||||
}
|
||||
|
||||
void CodeGenerator::cgConv(IRInstruction* inst) {
|
||||
Type toType = inst->getTypeParam();
|
||||
void CodeGenerator::cgConvToArr(IRInstruction* inst) {
|
||||
SSATmp* dst = inst->getDst();
|
||||
SSATmp* src = inst->getSrc(0);
|
||||
|
||||
ArgGroup args;
|
||||
args.typedValue(src);
|
||||
ArrayData*(*fPtr)(TypedValue) = new_singleton_array_helper;
|
||||
cgCallHelper(m_as, (TCA)fPtr, dst, kNoSyncPoint, args);
|
||||
}
|
||||
|
||||
void CodeGenerator::cgConvToBool(IRInstruction* inst) {
|
||||
Type fromType = inst->getSrc(0)->getType();
|
||||
SSATmp* dst = inst->getDst();
|
||||
SSATmp* src = inst->getSrc(0);
|
||||
@@ -1613,127 +1621,137 @@ void CodeGenerator::cgConv(IRInstruction* inst) {
|
||||
|
||||
bool srcIsConst = src->isConst();
|
||||
|
||||
if (toType == Type::Int) {
|
||||
if (fromType == Type::Bool) {
|
||||
// Bool -> Int is just a move
|
||||
if (srcIsConst) {
|
||||
int64_t constVal = src->getValRawInt();
|
||||
if (constVal == 0) {
|
||||
m_as.xor_reg64_reg64(dstReg, dstReg);
|
||||
} else {
|
||||
m_as.mov_imm64_reg(1, dstReg);
|
||||
}
|
||||
if (fromType.isNull()) {
|
||||
// Uninit/Null -> Bool (false)
|
||||
m_as.xor_reg64_reg64(dstReg, dstReg);
|
||||
} else if (fromType == Type::Bool) {
|
||||
// Bool -> Bool (nop!)
|
||||
if (srcIsConst) {
|
||||
int64_t constVal = src->getValRawInt();
|
||||
if (constVal == 0) {
|
||||
m_as.xor_reg64_reg64(dstReg, dstReg);
|
||||
} else {
|
||||
m_as.movzbl (rbyte(srcReg), r32(dstReg));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (fromType.isString()) {
|
||||
if (src->isConst()) {
|
||||
auto val = src->getValStr()->toInt64();
|
||||
m_as.mov_imm64_reg(val, dstReg);
|
||||
} else {
|
||||
ArgGroup args;
|
||||
args.ssa(src).imm(10);
|
||||
cgCallHelper(m_as,
|
||||
Transl::Call(getMethodPtr(&StringData::toInt64)),
|
||||
dstReg, kNoSyncPoint, args);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (toType == Type::Bool) {
|
||||
if (fromType.isNull()) {
|
||||
// Uninit/Null -> Bool (false)
|
||||
m_as.xor_reg64_reg64(dstReg, dstReg);
|
||||
} else if (fromType == Type::Bool) {
|
||||
// Bool -> Bool (nop!)
|
||||
if (srcIsConst) {
|
||||
int64_t constVal = src->getValRawInt();
|
||||
if (constVal == 0) {
|
||||
m_as.xor_reg64_reg64(dstReg, dstReg);
|
||||
} else {
|
||||
m_as.mov_imm64_reg(1, dstReg);
|
||||
}
|
||||
} else {
|
||||
emitMovRegReg(m_as, srcReg, dstReg);
|
||||
}
|
||||
} else if (fromType == Type::Int) {
|
||||
// Int -> Bool
|
||||
if (src->isConst()) {
|
||||
int64_t constVal = src->getValInt();
|
||||
if (constVal == 0) {
|
||||
m_as.xor_reg64_reg64(dstReg, dstReg);
|
||||
} else {
|
||||
m_as.mov_imm64_reg(1, dstReg);
|
||||
}
|
||||
} else {
|
||||
m_as.test_reg64_reg64(srcReg, srcReg);
|
||||
m_as.setne(rbyte(dstReg));
|
||||
m_as.mov_imm64_reg(1, dstReg);
|
||||
}
|
||||
} else {
|
||||
Transl::Call helper(nullptr);
|
||||
ArgGroup args;
|
||||
if (fromType == Type::Cell) {
|
||||
// Cell -> Bool
|
||||
args.typedValue(src);
|
||||
helper = Transl::Call((TCA)cellToBoolHelper);
|
||||
} else if (fromType.isString()) {
|
||||
// Str -> Bool
|
||||
args.ssa(src);
|
||||
helper = Transl::Call(getMethodPtr(&StringData::toBoolean));
|
||||
} else if (fromType.isArray()) {
|
||||
// Arr -> Bool
|
||||
args.ssa(src);
|
||||
helper = Transl::Call((TCA)arrToBoolHelper);
|
||||
} else if (fromType == Type::Obj) {
|
||||
// Obj -> Bool
|
||||
args.ssa(src);
|
||||
helper = Transl::Call(getMethodPtr(&ObjectData::o_toBoolean));
|
||||
emitMovRegReg(m_as, srcReg, dstReg);
|
||||
}
|
||||
} else if (fromType == Type::Int) {
|
||||
// Int -> Bool
|
||||
if (srcIsConst) {
|
||||
int64_t constVal = src->getValInt();
|
||||
if (constVal == 0) {
|
||||
m_as.xor_reg64_reg64(dstReg, dstReg);
|
||||
} else {
|
||||
// Dbl -> Bool
|
||||
CG_PUNT(Conv_Dbl_Bool);
|
||||
m_as.mov_imm64_reg(1, dstReg);
|
||||
}
|
||||
cgCallHelper(m_as, helper, dstReg, kNoSyncPoint, args);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (toType.isString()) {
|
||||
if (fromType == Type::Int) {
|
||||
// Int -> Str
|
||||
ArgGroup args;
|
||||
args.ssa(src);
|
||||
StringData*(*fPtr)(int64_t) = buildStringData;
|
||||
cgCallHelper(m_as, (TCA)fPtr,
|
||||
dst, kNoSyncPoint, args);
|
||||
} else if (fromType == Type::Bool) {
|
||||
// Bool -> Str
|
||||
m_as.testb(Reg8(int(srcReg)), Reg8(int(srcReg)));
|
||||
m_as.mov_imm64_reg((uint64_t)StringData::GetStaticString(""),
|
||||
dstReg);
|
||||
m_as.mov_imm64_reg((uint64_t)StringData::GetStaticString("1"),
|
||||
rScratch);
|
||||
m_as.cmov_reg64_reg64(CC_NZ, rScratch, dstReg);
|
||||
} else {
|
||||
CG_PUNT(Conv_toString);
|
||||
m_as.test_reg64_reg64(srcReg, srcReg);
|
||||
m_as.setne(rbyte(dstReg));
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (toType.isArray()) {
|
||||
} else {
|
||||
Transl::Call helper(nullptr);
|
||||
ArgGroup args;
|
||||
args.typedValue(src);
|
||||
ArrayData*(*fPtr)(TypedValue) = new_singleton_array_helper;
|
||||
cgCallHelper(m_as, (TCA)fPtr, dst, kNoSyncPoint, args);
|
||||
if (fromType == Type::Cell) {
|
||||
// Cell -> Bool
|
||||
args.typedValue(src);
|
||||
helper = Transl::Call((TCA)cellToBoolHelper);
|
||||
} else if (fromType.isString()) {
|
||||
// Str -> Bool
|
||||
args.ssa(src);
|
||||
helper = Transl::Call(getMethodPtr(&StringData::toBoolean));
|
||||
} else if (fromType.isArray()) {
|
||||
// Arr -> Bool
|
||||
args.ssa(src);
|
||||
helper = Transl::Call((TCA)arrToBoolHelper);
|
||||
} else if (fromType == Type::Obj) {
|
||||
// Obj -> Bool
|
||||
args.ssa(src);
|
||||
helper = Transl::Call(getMethodPtr(&ObjectData::o_toBoolean));
|
||||
} else {
|
||||
// Dbl -> Bool
|
||||
CG_PUNT(Conv_Dbl_Bool);
|
||||
}
|
||||
cgCallHelper(m_as, helper, dstReg, kNoSyncPoint, args);
|
||||
}
|
||||
}
|
||||
|
||||
void CodeGenerator::cgConvToDbl(IRInstruction* inst) {
|
||||
CG_PUNT(ConvToDbl);
|
||||
}
|
||||
|
||||
void CodeGenerator::cgConvToInt(IRInstruction* inst) {
|
||||
Type fromType = inst->getSrc(0)->getType();
|
||||
SSATmp* dst = inst->getDst();
|
||||
SSATmp* src = inst->getSrc(0);
|
||||
|
||||
auto dstReg = dst->getReg();
|
||||
auto srcReg = src->getReg();
|
||||
|
||||
bool srcIsConst = src->isConst();
|
||||
|
||||
if (fromType == Type::Bool) {
|
||||
// Bool -> Int is just a move
|
||||
if (srcIsConst) {
|
||||
int64_t constVal = src->getValRawInt();
|
||||
if (constVal == 0) {
|
||||
m_as.xor_reg64_reg64(dstReg, dstReg);
|
||||
} else {
|
||||
m_as.mov_imm64_reg(1, dstReg);
|
||||
}
|
||||
} else {
|
||||
m_as.movzbl (rbyte(srcReg), r32(dstReg));
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (fromType.isString()) {
|
||||
if (srcIsConst) {
|
||||
auto val = src->getValStr()->toInt64();
|
||||
m_as.mov_imm64_reg(val, dstReg);
|
||||
} else {
|
||||
ArgGroup args;
|
||||
args.ssa(src).imm(10);
|
||||
cgCallHelper(m_as,
|
||||
Transl::Call(getMethodPtr(&StringData::toInt64)),
|
||||
dstReg, kNoSyncPoint, args);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Add handling of conversions
|
||||
CG_PUNT(Conv);
|
||||
}
|
||||
|
||||
void CodeGenerator::cgConvToObj(IRInstruction* inst) {
|
||||
CG_PUNT(ConvToObj);
|
||||
}
|
||||
|
||||
void CodeGenerator::cgConvToStr(IRInstruction* inst) {
|
||||
Type fromType = inst->getSrc(0)->getType();
|
||||
SSATmp* dst = inst->getDst();
|
||||
SSATmp* src = inst->getSrc(0);
|
||||
|
||||
auto dstReg = dst->getReg();
|
||||
auto srcReg = src->getReg();
|
||||
|
||||
if (fromType == Type::Int) {
|
||||
// Int -> Str
|
||||
ArgGroup args;
|
||||
args.ssa(src);
|
||||
StringData*(*fPtr)(int64_t) = buildStringData;
|
||||
cgCallHelper(m_as, (TCA)fPtr,
|
||||
dst, kNoSyncPoint, args);
|
||||
} else if (fromType == Type::Bool) {
|
||||
// Bool -> Str
|
||||
m_as.testb(Reg8(int(srcReg)), Reg8(int(srcReg)));
|
||||
m_as.mov_imm64_reg((uint64_t)StringData::GetStaticString(""),
|
||||
dstReg);
|
||||
m_as.mov_imm64_reg((uint64_t)StringData::GetStaticString("1"),
|
||||
rScratch);
|
||||
m_as.cmov_reg64_reg64(CC_NZ, rScratch, dstReg);
|
||||
} else {
|
||||
CG_PUNT(ConvToString);
|
||||
}
|
||||
}
|
||||
|
||||
void CodeGenerator::cgUnboxPtr(IRInstruction* inst) {
|
||||
SSATmp* dst = inst->getDst();
|
||||
SSATmp* src = inst->getSrc(0);
|
||||
|
||||
@@ -164,7 +164,12 @@ O(OpAnd, D(Int), SNumInt SNumInt, C) \
|
||||
O(OpOr, D(Int), SNum SNum, C) \
|
||||
O(OpXor, D(Int), SNumInt SNumInt, C) \
|
||||
O(OpMul, DParam, SNum SNum, C) \
|
||||
O(Conv, DParam, S(Gen), C|N) \
|
||||
O(ConvToArr, DParam, S(Gen), C|N) \
|
||||
O(ConvToBool, DParam, S(Gen), C|N) \
|
||||
O(ConvToDbl, DParam, S(Gen), C|N) \
|
||||
O(ConvToInt, DParam, S(Gen), C|N) \
|
||||
O(ConvToObj, DParam, S(Gen), C|N) \
|
||||
O(ConvToStr, DParam, S(Gen), C|N) \
|
||||
O(ExtendsClass, D(Bool), S(Cls) C(Cls), C) \
|
||||
O(IsTypeMem, D(Bool), S(PtrToGen), NA) \
|
||||
O(IsNTypeMem, D(Bool), S(PtrToGen), NA) \
|
||||
@@ -2180,8 +2185,7 @@ int32_t spillValueCells(IRInstruction* spillStack);
|
||||
constexpr int kSpillStackActRecExtraArgs = 4;
|
||||
|
||||
inline bool isConvIntOrPtrToBool(IRInstruction* instr) {
|
||||
if (!(instr->getOpcode() == Conv &&
|
||||
instr->getTypeParam() == Type::Bool)) {
|
||||
if (instr->getOpcode() != ConvToBool) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -637,16 +637,16 @@ void LinearScan::computePreColoringHint() {
|
||||
}
|
||||
break;
|
||||
case IterInit:
|
||||
{
|
||||
m_preColoringHint.add(inst->getSrc(0), 0, 1);
|
||||
}
|
||||
break;
|
||||
case Conv:
|
||||
{
|
||||
SSATmp* src = inst->getSrc(0);
|
||||
Type toType = inst->getTypeParam();
|
||||
Type fromType = src->getType();
|
||||
if (toType == Type::Bool) {
|
||||
{
|
||||
m_preColoringHint.add(inst->getSrc(0), 0, 1);
|
||||
}
|
||||
break;
|
||||
case ConvToArr:
|
||||
break;
|
||||
case ConvToBool:
|
||||
{
|
||||
SSATmp* src = inst->getSrc(0);
|
||||
Type fromType = src->getType();
|
||||
if (fromType == Type::Cell) {
|
||||
m_preColoringHint.add(src, 0, 0);
|
||||
m_preColoringHint.add(src, 1, 1);
|
||||
@@ -656,11 +656,23 @@ void LinearScan::computePreColoringHint() {
|
||||
fromType == Type::Obj) {
|
||||
m_preColoringHint.add(src, 0, 0);
|
||||
}
|
||||
} else if (fromType.isString() && toType == Type::Int) {
|
||||
m_preColoringHint.add(src, 0, 0);
|
||||
break;
|
||||
}
|
||||
case ConvToDbl:
|
||||
break;
|
||||
case ConvToInt:
|
||||
{
|
||||
SSATmp* src = inst->getSrc(0);
|
||||
Type fromType = src->getType();
|
||||
if (fromType.isString()) {
|
||||
m_preColoringHint.add(src, 0, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ConvToObj:
|
||||
break;
|
||||
case ConvToStr:
|
||||
break;
|
||||
}
|
||||
case InstanceOf:
|
||||
case NInstanceOf:
|
||||
case JmpInstanceOf:
|
||||
|
||||
@@ -95,7 +95,12 @@ SSATmp* Simplifier::simplify(IRInstruction* inst) {
|
||||
case Concat: return simplifyConcat(src1, src2);
|
||||
case Mov: return simplifyMov(src1);
|
||||
case LdClsPropAddr: return simplifyLdClsPropAddr(inst);
|
||||
case Conv: return simplifyConv(inst);
|
||||
case ConvToArr: return simplifyConvToArr(inst);
|
||||
case ConvToBool: return simplifyConvToBool(inst);
|
||||
case ConvToDbl: return simplifyConvToDbl(inst);
|
||||
case ConvToInt: return simplifyConvToInt(inst);
|
||||
case ConvToObj: return simplifyConvToObj(inst);
|
||||
case ConvToStr: return simplifyConvToStr(inst);
|
||||
case Unbox: return simplifyUnbox(inst);
|
||||
case UnboxPtr: return simplifyUnboxPtr(inst);
|
||||
case IsType:
|
||||
@@ -418,7 +423,7 @@ SSATmp* Simplifier::simplifyNot(SSATmp* src) {
|
||||
|
||||
// TODO: Add more algebraic simplification rules for NOT
|
||||
switch (op) {
|
||||
case Conv:
|
||||
case ConvToBool:
|
||||
return simplifyNot(inst->getSrc(0));
|
||||
case OpXor: {
|
||||
// !!X --> bool(X)
|
||||
@@ -1082,108 +1087,141 @@ SSATmp* Simplifier::simplifyConcat(SSATmp* src1, SSATmp* src2) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SSATmp* Simplifier::simplifyConv(IRInstruction* inst) {
|
||||
SSATmp* src = inst->getSrc(0);
|
||||
Type type = src->getType();
|
||||
Type toType = inst->getTypeParam();
|
||||
if (toType == type) {
|
||||
SSATmp* Simplifier::simplifyConvToArr(IRInstruction* inst) {
|
||||
SSATmp* src = inst->getSrc(0);
|
||||
Type srcType = src->getType();
|
||||
if (srcType == Type::Arr) {
|
||||
return src;
|
||||
}
|
||||
if (toType == Type::Str) {
|
||||
if (type.isString()) {
|
||||
return src;
|
||||
if (srcType.isNull()) {
|
||||
return m_tb->genDefConst(HphpArray::GetStaticEmptyArray());
|
||||
}
|
||||
// If the src is a constant, the result can be a constant array.
|
||||
if (src->isConst()) {
|
||||
switch (srcType.toDataType()) {
|
||||
case KindOfBoolean:
|
||||
case KindOfInt64:
|
||||
case KindOfDouble:
|
||||
case KindOfStaticString: {
|
||||
auto arr = ArrayData::Create(src->getValVariant());
|
||||
arr->incRefCount();
|
||||
return m_tb->genDefConst(ArrayData::GetScalarArray(arr));
|
||||
}
|
||||
// arrays always get converted to the string "Array"
|
||||
if (type.isArray()) {
|
||||
return m_tb->genDefConst(StringData::GetStaticString("Array"));
|
||||
}
|
||||
if (type.isNull()) {
|
||||
return m_tb->genDefConst(StringData::GetStaticString(""));
|
||||
}
|
||||
if (src->isConst()) {
|
||||
if (type == Type::Bool) {
|
||||
if (src->getValBool()) {
|
||||
return m_tb->genDefConst(StringData::GetStaticString("1"));
|
||||
}
|
||||
return m_tb->genDefConst(StringData::GetStaticString(""));
|
||||
}
|
||||
if (type == Type::Int) {
|
||||
std::stringstream ss;
|
||||
ss << src->getValInt();
|
||||
return m_tb->genDefConst(StringData::GetStaticString(ss.str()));
|
||||
}
|
||||
if (type == Type::Dbl) {
|
||||
// TODO constant dbl to string
|
||||
}
|
||||
default:
|
||||
assert(!srcType.isArray());
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (toType == Type::Bool) {
|
||||
if (type.isNull()) {
|
||||
return genDefBool(false);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SSATmp* Simplifier::simplifyConvToBool(IRInstruction* inst) {
|
||||
SSATmp* src = inst->getSrc(0);
|
||||
Type srcType = src->getType();
|
||||
if (srcType == Type::Bool) {
|
||||
return src;
|
||||
}
|
||||
if (srcType.isNull()) {
|
||||
return genDefBool(false);
|
||||
}
|
||||
if (srcType == Type::Obj) {
|
||||
return genDefBool(true);
|
||||
}
|
||||
if (src->isConst()) {
|
||||
if (srcType == Type::Int) {
|
||||
return genDefBool(bool(src->getValInt()));
|
||||
}
|
||||
if (type == Type::Obj) {
|
||||
if (srcType == Type::StaticStr) {
|
||||
// only the strings "", and "0" convert to false, all other strings
|
||||
// are converted to true
|
||||
const StringData* str = src->getValStr();
|
||||
return genDefBool(!str->empty() && !str->isZero());
|
||||
}
|
||||
if (srcType.isArray()) {
|
||||
if (src->getValArr()->empty()) {
|
||||
return genDefBool(false);
|
||||
}
|
||||
return genDefBool(true);
|
||||
}
|
||||
if (src->isConst()) {
|
||||
if (type == Type::Int) {
|
||||
return genDefBool(bool(src->getValInt()));
|
||||
}
|
||||
if (type == Type::StaticStr) {
|
||||
// only the strings "", and "0" convert to false, all other strings
|
||||
// are converted to true
|
||||
const StringData* str = src->getValStr();
|
||||
return genDefBool(!str->empty() && !str->isZero());
|
||||
}
|
||||
if (type.isArray()) {
|
||||
if (src->getValArr()->empty()) {
|
||||
return genDefBool(false);
|
||||
}
|
||||
return genDefBool(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (toType == Type::Int) {
|
||||
if (type.isNull()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SSATmp* Simplifier::simplifyConvToDbl(IRInstruction* inst) {
|
||||
SSATmp* src = inst->getSrc(0);
|
||||
Type type = src->getType();
|
||||
if (type == Type::Dbl) {
|
||||
return src;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SSATmp* Simplifier::simplifyConvToInt(IRInstruction* inst) {
|
||||
SSATmp* src = inst->getSrc(0);
|
||||
Type srcType = src->getType();
|
||||
if (srcType == Type::Int) {
|
||||
return src;
|
||||
}
|
||||
if (srcType.isNull()) {
|
||||
return genDefInt(0);
|
||||
}
|
||||
if (src->isConst()) {
|
||||
if (src->getType() == Type::Bool) {
|
||||
return genDefInt(int(src->getValBool()));
|
||||
}
|
||||
if (srcType == Type::StaticStr) {
|
||||
const StringData *str = src->getValStr();
|
||||
if (str->isInteger()) {
|
||||
return genDefInt(str->toInt64());
|
||||
}
|
||||
return genDefInt(0);
|
||||
}
|
||||
if (src->isConst()) {
|
||||
if (src->getType() == Type::Bool) {
|
||||
return genDefInt(int(src->getValBool()));
|
||||
}
|
||||
if (type == Type::StaticStr) {
|
||||
const StringData *str = src->getValStr();
|
||||
if (str->isInteger()) {
|
||||
return genDefInt(str->toInt64());
|
||||
}
|
||||
if (srcType.isArray()) {
|
||||
if (src->getValArr()->empty()) {
|
||||
return genDefInt(0);
|
||||
}
|
||||
if (type.isArray()) {
|
||||
if (src->getValArr()->empty()) {
|
||||
return genDefInt(0);
|
||||
}
|
||||
return genDefInt(1);
|
||||
}
|
||||
return genDefInt(1);
|
||||
}
|
||||
}
|
||||
if (toType == Type::Arr) {
|
||||
if (type.isNull()) {
|
||||
return m_tb->genDefConst(HphpArray::GetStaticEmptyArray());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SSATmp* Simplifier::simplifyConvToObj(IRInstruction* inst) {
|
||||
SSATmp* src = inst->getSrc(0);
|
||||
Type srcType = src->getType();
|
||||
if (srcType == Type::Obj) {
|
||||
return src;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SSATmp* Simplifier::simplifyConvToStr(IRInstruction* inst) {
|
||||
SSATmp* src = inst->getSrc(0);
|
||||
Type srcType = src->getType();
|
||||
if (srcType.isString()) {
|
||||
return src;
|
||||
}
|
||||
// arrays always get converted to the string "Array"
|
||||
if (srcType.isArray()) {
|
||||
return m_tb->genDefConst(StringData::GetStaticString("Array"));
|
||||
}
|
||||
if (srcType.isNull()) {
|
||||
return m_tb->genDefConst(StringData::GetStaticString(""));
|
||||
}
|
||||
if (src->isConst()) {
|
||||
if (srcType == Type::Bool) {
|
||||
if (src->getValBool()) {
|
||||
return m_tb->genDefConst(StringData::GetStaticString("1"));
|
||||
}
|
||||
return m_tb->genDefConst(StringData::GetStaticString(""));
|
||||
}
|
||||
// If the src is a constant, the result can be a constant array.
|
||||
if (src->isConst()) {
|
||||
switch (type.toDataType()) {
|
||||
case KindOfBoolean:
|
||||
case KindOfInt64:
|
||||
case KindOfDouble:
|
||||
case KindOfStaticString: {
|
||||
auto arr = ArrayData::Create(src->getValVariant());
|
||||
arr->incRefCount();
|
||||
return m_tb->genDefConst(ArrayData::GetScalarArray(arr));
|
||||
}
|
||||
default:
|
||||
assert(!type.isArray());
|
||||
break;
|
||||
}
|
||||
if (srcType == Type::Int) {
|
||||
std::stringstream ss;
|
||||
ss << src->getValInt();
|
||||
return m_tb->genDefConst(StringData::GetStaticString(ss.str()));
|
||||
}
|
||||
if (srcType == Type::Dbl) {
|
||||
// TODO constant dbl to string
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
|
||||
@@ -62,7 +62,12 @@ private:
|
||||
SSATmp* simplifyIsType(IRInstruction*);
|
||||
SSATmp* simplifyJmpIsType(IRInstruction*);
|
||||
SSATmp* simplifyConcat(SSATmp* src1, SSATmp* src2);
|
||||
SSATmp* simplifyConv(IRInstruction*);
|
||||
SSATmp* simplifyConvToArr(IRInstruction*);
|
||||
SSATmp* simplifyConvToBool(IRInstruction*);
|
||||
SSATmp* simplifyConvToDbl(IRInstruction*);
|
||||
SSATmp* simplifyConvToInt(IRInstruction*);
|
||||
SSATmp* simplifyConvToObj(IRInstruction*);
|
||||
SSATmp* simplifyConvToStr(IRInstruction*);
|
||||
SSATmp* simplifyUnbox(IRInstruction*);
|
||||
SSATmp* simplifyUnboxPtr(IRInstruction*);
|
||||
SSATmp* simplifyCheckInit(IRInstruction* inst);
|
||||
|
||||
@@ -382,32 +382,32 @@ SSATmp* TraceBuilder::genDefNone() {
|
||||
}
|
||||
|
||||
SSATmp* TraceBuilder::genConvToInt(SSATmp* src) {
|
||||
return gen(Conv, Type::Int, src);
|
||||
return gen(ConvToInt, Type::Int, src);
|
||||
}
|
||||
|
||||
SSATmp* TraceBuilder::genConvToDbl(SSATmp* src) {
|
||||
return gen(Conv, Type::Dbl, src);
|
||||
return gen(ConvToDbl, Type::Dbl, src);
|
||||
}
|
||||
|
||||
SSATmp* TraceBuilder::genConvToStr(SSATmp* src) {
|
||||
if (src->getType() == Type::Bool) {
|
||||
// Bool to string code sequence loads static strings
|
||||
return gen(Conv, Type::StaticStr, src);
|
||||
return gen(ConvToStr, Type::StaticStr, src);
|
||||
} else {
|
||||
return gen(Conv, Type::Str, src);
|
||||
return gen(ConvToStr, Type::Str, src);
|
||||
}
|
||||
}
|
||||
|
||||
SSATmp* TraceBuilder::genConvToArr(SSATmp* src) {
|
||||
return gen(Conv, Type::Arr, src);
|
||||
return gen(ConvToArr, Type::Arr, src);
|
||||
}
|
||||
|
||||
SSATmp* TraceBuilder::genConvToObj(SSATmp* src) {
|
||||
return gen(Conv, Type::Obj, src);
|
||||
return gen(ConvToObj, Type::Obj, src);
|
||||
}
|
||||
|
||||
SSATmp* TraceBuilder::genConvToBool(SSATmp* src) {
|
||||
return gen(Conv, Type::Bool, src);
|
||||
return gen(ConvToBool, Type::Bool, src);
|
||||
}
|
||||
|
||||
SSATmp* TraceBuilder::genCmp(Opcode opc, SSATmp* src1, SSATmp* src2) {
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário