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:
hermanv
2013-03-19 14:00:29 -07:00
commit de Sara Golemon
commit 3718c612ed
7 arquivos alterados com 308 adições e 225 exclusões
+8 -2
Ver Arquivo
@@ -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.
+129 -111
Ver Arquivo
@@ -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);
+7 -3
Ver Arquivo
@@ -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;
}
+25 -13
Ver Arquivo
@@ -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:
+126 -88
Ver Arquivo
@@ -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;
+6 -1
Ver Arquivo
@@ -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) {