Conversions in IR

Rolls up all previous diffs into a single diff and uses the CALL_OPCODE macro.
Esse commit está contido em:
hermanv
2013-04-17 22:19:15 -07:00
commit de Sara Golemon
commit 5e6cce4db5
16 arquivos alterados com 489 adições e 443 exclusões
+19 -6
Ver Arquivo
@@ -398,21 +398,34 @@ D:Arr = ConvDblToArr S0:Dbl
D:Arr = ConvIntToArr S0:Int
D:Arr = ConvObjToArr S0:Obj
D:Arr = ConvStrToArr S0:Str
D:Arr = ConvGenToArr S0:Gen
D:Bool = ConvToBool S0:Gen
D:Arr = ConvCellToArr S0:Cell
D:Bool = ConvArrToBool S0:Arr
D:Bool = ConvDblToBool S0:Dbl
D:Bool = ConvIntToBool S0:Int
D:Bool = ConvStrToBool S0:Str
D:Bool = ConvCellToBool S0:Cell
D:Dbl = ConvArrToDbl S0:Arr
D:Dbl = ConvBoolToDbl S0:Bool
D:Dbl = ConvIntToDbl S0:Int
D:Dbl = ConvObjToDbl S0:Obj
D:Dbl = ConvStrToDbl S0:Str
D:Dbl = ConvGenToDbl S0:Gen
D:Dbl = ConvCellToDbl S0:Cell
D:Int = ConvArrToInt S0:Arr
D:Int = ConvDblToInt S0:Dbl
D:Int = ConvObjToInt S0:Obj
D:Int = ConvStrToInt S0:Str
D:Int = ConvGenToInt S0:Gen
D:Obj = ConvoObj S0:Gen
D:Str = ConvToStr S0:Gen
D:Int = ConvCellToInt S0:Cell
D:Obj = ConvCellToObj S0:Cell
D:StaticStr = ConvBoolToStr S0:Bool
D:Str = ConvDblToStr S0:Dbl
D:Str = ConvIntToStr S0:Int
D:Str = ConvObjToStr S0:Obj
D:Str = ConvCellToStr S0:Cell
Convert S0 from its current type to the destination type, according to the PHP
semantics of such a conversion.
+23
Ver Arquivo
@@ -20,6 +20,7 @@
#include <runtime/base/util/exceptions.h>
#include <util/alloc.h>
#include <math.h>
#include <runtime/base/zend/zend_printf.h>
#include <runtime/base/zend/zend_string.h>
#include <runtime/base/zend/zend_strtod.h>
#include <runtime/base/complex_types.h>
@@ -42,6 +43,28 @@ typedef tbb::concurrent_unordered_map<const StringData *, uint32_t,
string_data_same> StringDataMap;
static StringDataMap *s_stringDataMap;
const StringData* StringData::convert_double_helper(double n) {
char *buf;
StringData* result;
if (n == 0.0) n = 0.0; // so to avoid "-0" output
vspprintf(&buf, 0, "%.*G", 14, n);
result = StringData::GetStaticString(buf);
free(buf);
return result;
}
const StringData* StringData::convert_integer_helper(int64_t n) {
char tmpbuf[21];
char *p;
int is_negative;
int len;
tmpbuf[20] = '\0';
p = conv_10(n, &is_negative, &tmpbuf[20], &len);
return StringData::GetStaticString(p);
}
size_t StringData::GetStaticStringCount() {
if (!s_stringDataMap) return 0;
return s_stringDataMap->size();
+2
Ver Arquivo
@@ -215,6 +215,8 @@ class StringData {
public:
void append(StringSlice r) { append(r.ptr, r.len); }
void append(const char *s, int len);
static const StringData* convert_double_helper(double n);
static const StringData* convert_integer_helper(int64_t n);
StringData *copy(bool sharedMemory = false) const;
MutableSlice reserve(int capacity);
MutableSlice mutableSlice() {
+2 -13
Ver Arquivo
@@ -40,27 +40,16 @@ StringData const **String::converted_integers;
String::IntegerStringDataMap String::integer_string_data_map;
static const StringData *convert_integer_helper(int64_t n) {
char tmpbuf[21];
char *p;
int is_negative;
int len;
tmpbuf[20] = '\0';
p = conv_10(n, &is_negative, &tmpbuf[20], &len);
return StringData::GetStaticString(p);
}
void String::PreConvertInteger(int64_t n) {
IntegerStringDataMap::const_iterator it =
integer_string_data_map.find(n);
if (it != integer_string_data_map.end()) return;
integer_string_data_map[n] = convert_integer_helper(n);
integer_string_data_map[n] = StringData::convert_integer_helper(n);
}
const StringData *String::ConvertInteger(int64_t n) {
StringData const **psd = converted_integers + n;
const StringData *sd = convert_integer_helper(n);
const StringData *sd = StringData::convert_integer_helper(n);
*psd = sd;
return sd;
}
+74 -265
Ver Arquivo
@@ -315,6 +315,36 @@ CALL_OPCODE(AddElemIntKey)
CALL_OPCODE(AddNewElem)
CALL_OPCODE(ArrayAdd)
CALL_OPCODE(Box)
CALL_OPCODE(ConvBoolToArr);
CALL_OPCODE(ConvDblToArr);
CALL_OPCODE(ConvIntToArr);
CALL_OPCODE(ConvObjToArr);
CALL_OPCODE(ConvStrToArr);
CALL_OPCODE(ConvCellToArr);
CALL_OPCODE(ConvArrToBool);
CALL_OPCODE(ConvStrToBool);
CALL_OPCODE(ConvCellToBool);
CALL_OPCODE(ConvArrToDbl);
CALL_OPCODE(ConvObjToDbl);
CALL_OPCODE(ConvStrToDbl);
CALL_OPCODE(ConvCellToDbl);
CALL_OPCODE(ConvArrToInt);
CALL_OPCODE(ConvDblToInt);
CALL_OPCODE(ConvObjToInt);
CALL_OPCODE(ConvStrToInt);
CALL_OPCODE(ConvCellToInt);
CALL_OPCODE(ConvCellToObj);
CALL_OPCODE(ConvDblToStr);
CALL_OPCODE(ConvIntToStr);
CALL_OPCODE(ConvObjToStr);
CALL_OPCODE(ConvCellToStr);
CALL_OPCODE(CreateCont)
CALL_OPCODE(FillContLocals)
CALL_OPCODE(NewArray)
@@ -1101,34 +1131,6 @@ void CodeGenerator::cgOpMul(IRInstruction* inst) {
Commutative);
}
// Runtime helpers
HOT_FUNC_VM static int64_t arrToBoolHelper(const ArrayData *a) {
return a->size() != 0;
}
HOT_FUNC_VM static int64_t cellToBoolHelper(TypedValue tv) {
if (IS_NULL_TYPE(tv.m_type)) {
return 0;
}
if (tv.m_type <= KindOfInt64) {
return tv.m_data.num ? 1 : 0;
}
switch (tv.m_type) {
case KindOfDouble: return tv.m_data.dbl != 0;
case KindOfStaticString:
case KindOfString: return tv.m_data.pstr->toBoolean();
case KindOfArray: return tv.m_data.parr->size() != 0;
case KindOfObject: return tv.m_data.pobj->o_toBoolean();
default:
assert(false);
break;
}
return 0;
}
///////////////////////////////////////////////////////////////////////////////
// Comparison Operators
///////////////////////////////////////////////////////////////////////////////
@@ -1612,138 +1614,48 @@ asm_label(a, falseLabel);
asm_label(a, out);
}
// The assumption here is that the overall cost of allocating
// the array swamps the cost of putting a simple value in to
// a typed value, so there is no need for further type specialization.
void CodeGenerator::cgConvBoolToArr(IRInstruction* inst) {
cgConvGenToArr(inst);
}
void CodeGenerator::cgConvDblToArr(IRInstruction* inst) {
cgConvGenToArr(inst);
}
void CodeGenerator::cgConvIntToArr(IRInstruction* inst) {
cgConvGenToArr(inst);
}
void CodeGenerator::cgConvObjToArr(IRInstruction* inst) {
cgConvGenToArr(inst);
}
void CodeGenerator::cgConvStrToArr(IRInstruction* inst) {
cgConvGenToArr(inst);
}
// So why have all of these different IR instructions instead
// of just ConvGenToArr? Because we need at least two variants
// and we don't want to overload opcodes and we want consistency.
ArrayData* convGenToArrHelper(TypedValue value) {
// Note: the call sites of this function all assume that
// no user code will run and no recoverable exceptions will
// occur while running this code. This seems trivially true
// in all cases but converting objects to arrays. It also
// seems true for that case as well, since the resulting array
// is essentially metadata for the object. If that is not true,
// you might end up looking at this code in a debugger and now
// you know why.
tvCastToArrayInPlace(&value); // consumes a ref on counted values
return value.m_data.parr;
}
void CodeGenerator::cgConvGenToArr(IRInstruction* inst) {
void CodeGenerator::cgConvDblToBool(IRInstruction* inst) {
SSATmp* dst = inst->getDst();
SSATmp* src = inst->getSrc(0);
ArgGroup args;
args.typedValue(src);
ArrayData*(*fPtr)(TypedValue) = convGenToArrHelper;
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);
auto dstReg = dst->getReg();
assert(dstReg != InvalidReg);
SSATmp* src = inst->getSrc(0);
auto srcReg = src->getReg();
bool srcIsConst = src->isConst();
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);
}
if (srcReg == InvalidReg) {
assert(src->isConst());
double constVal = src->getValDbl();
if (constVal == 0.0) {
m_as.xor_reg64_reg64(dstReg, dstReg);
} else {
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 {
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));
} else {
// Dbl -> Bool
CG_PUNT(Conv_Dbl_Bool);
}
cgCallHelper(m_as, helper, dstReg, kNoSyncPoint, args);
m_as.movq(srcReg, dstReg);
m_as.shlq(1, dstReg); // 0.0 stays zero and -0.0 is now 0.0
m_as.setne(rbyte(dstReg)); // lower byte becomes 1 if dstReg != 0
m_as.movzbl(rbyte(dstReg), r32(dstReg));
}
}
static int64_t arrayToDoubleHelper(ArrayData* value) {
union {
int64_t intval;
double dblval;
} u;
u.dblval = value->empty() ? 0 : 1;
return u.intval;
}
void CodeGenerator::cgConvArrToDbl(IRInstruction* inst) {
void CodeGenerator::cgConvIntToBool(IRInstruction* inst) {
SSATmp* dst = inst->getDst();
auto dstReg = dst->getReg();
assert(dstReg != InvalidReg);
SSATmp* src = inst->getSrc(0);
ArgGroup args;
args.ssa(src);
int64_t (*fPtr)(ArrayData*) = arrayToDoubleHelper;
cgCallHelper(m_as, (TCA)fPtr, dst, kNoSyncPoint, args);
auto srcReg = src->getReg();
if (srcReg == InvalidReg) {
assert(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.movzbl(rbyte(dstReg), r32(dstReg));
}
}
void CodeGenerator::cgConvBoolToDbl(IRInstruction* inst) {
@@ -1796,42 +1708,6 @@ void CodeGenerator::cgConvIntToDbl(IRInstruction* inst) {
m_as.mov_xmm_reg64(xmm0, dstReg);
}
void CodeGenerator::cgConvObjToDbl(IRInstruction* inst) {
cgConvGenToDbl(inst);
}
void CodeGenerator::cgConvStrToDbl(IRInstruction* inst) {
cgConvGenToDbl(inst);
}
HOT_FUNC_VM static int64_t genToDblHelper(TypedValue value) {
tvCastToDoubleInPlace(&value); // this will decrease the ref count
// of the current object in value.
return value.m_data.num;
}
void CodeGenerator::cgConvGenToDbl(IRInstruction* inst) {
SSATmp* dst = inst->getDst();
SSATmp* src = inst->getSrc(0);
ArgGroup args;
args.typedValue(src);
int64_t (*fPtr)(TypedValue) = genToDblHelper;
cgCallHelper(m_as, (TCA)fPtr, dst, kSyncPoint, args);
}
static int64_t arrayToIntHelper(ArrayData* value) {
return value->empty() ? 0 : 1;
}
void CodeGenerator::cgConvArrToInt(IRInstruction* inst) {
SSATmp* dst = inst->getDst();
SSATmp* src = inst->getSrc(0);
ArgGroup args;
args.ssa(src);
int64_t (*fPtr)(ArrayData*) = arrayToIntHelper;
cgCallHelper(m_as, (TCA)fPtr, dst, kNoSyncPoint, args);
}
void CodeGenerator::cgConvBoolToInt(IRInstruction* inst) {
SSATmp* dst = inst->getDst();
auto dstReg = dst->getReg();
@@ -1851,92 +1727,25 @@ void CodeGenerator::cgConvBoolToInt(IRInstruction* inst) {
}
}
HOT_FUNC_VM static int64_t doubleToIntHelper(int64_t value) {
union {
int64_t intval;
double dblval;
} u;
u.intval = value;
double d = u.dblval;
return (d >= 0 ? d > std::numeric_limits<uint64_t>::max() ? 0u :
(uint64_t)d : (int64_t)d);
}
void CodeGenerator::cgConvDblToInt(IRInstruction* inst) {
SSATmp* dst = inst->getDst();
SSATmp* src = inst->getSrc(0);
ArgGroup args;
args.typedValue(src);
int64_t (*fPtr)(int64_t) = doubleToIntHelper;
cgCallHelper(m_as, (TCA)fPtr, dst, kNoSyncPoint, args);
}
void CodeGenerator::cgConvObjToInt(IRInstruction* inst) {
// Never cheap, so just use the general logic.
cgConvGenToInt(inst);
}
void CodeGenerator::cgConvStrToInt(IRInstruction* inst) {
void CodeGenerator::cgConvBoolToStr(IRInstruction* inst) {
SSATmp* dst = inst->getDst();
auto dstReg = dst->getReg();
assert(dstReg != InvalidReg);
SSATmp* src = inst->getSrc(0);
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);
}
}
static int64_t genToIntHelper(TypedValue value) {
tvCastToInt64InPlace(&value); // this will decrease the ref count
// of the current object in value.
return value.m_data.num;
}
void CodeGenerator::cgConvGenToInt(IRInstruction* inst) {
SSATmp* dst = inst->getDst();
SSATmp* src = inst->getSrc(0);
ArgGroup args;
args.typedValue(src);
int64_t (*fPtr)(TypedValue) = genToIntHelper;
cgCallHelper(m_as, (TCA)fPtr, dst, kSyncPoint, args);
}
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);
assert(src->isConst() == (srcReg == InvalidReg));
if (srcReg == InvalidReg) {
auto constVal = src->getValBool();
if (!constVal) {
m_as.mov_imm64_reg((uint64_t)StringData::GetStaticString(""), dstReg);
} else {
m_as.mov_imm64_reg((uint64_t)StringData::GetStaticString("1"), dstReg);
}
} else {
CG_PUNT(ConvToString);
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);
}
}
+33 -18
Ver Arquivo
@@ -1,4 +1,4 @@
/*
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
@@ -2153,7 +2153,7 @@ void HhbcTranslator::emitCastArray() {
} else if (fromType.isObj()) {
push(m_tb->gen(ConvObjToArr, src));
} else {
push(m_tb->gen(ConvGenToArr, src));
push(m_tb->gen(ConvCellToArr, src));
}
}
@@ -2184,7 +2184,7 @@ void HhbcTranslator::emitCastDouble() {
push(m_tb->gen(ConvObjToDbl, src));
} else {
spillStack(); // may throw
push(m_tb->gen(ConvGenToDbl, src));
push(m_tb->gen(ConvCellToDbl, src));
}
}
@@ -2210,28 +2210,43 @@ void HhbcTranslator::emitCastInt() {
push(m_tb->gen(ConvObjToInt, src));
} else {
spillStack(); // may throw
push(m_tb->gen(ConvGenToInt, src));
push(m_tb->gen(ConvCellToInt, src));
}
}
void HhbcTranslator::emitCastObject() {
SSATmp* src = popC();
Type srcType = src->getType();
if (srcType.isObj()) {
push(src);
} else {
push(m_tb->gen(ConvCellToObj, src));
}
}
void HhbcTranslator::emitCastString() {
SSATmp* src = popC();
Type fromType = src->getType();
if (fromType == Type::Cell) {
PUNT(CastString_Cell);
} else if (fromType == Type::Obj) {
// call the toString helper on object
PUNT(CastString_Obj);
if (fromType.isString()) {
push(src);
} else if (fromType.isNull()) {
push(m_tb->genDefConst(StringData::GetStaticString("")));
} else if (fromType.isArray()) {
push(m_tb->genDefConst(StringData::GetStaticString("Array")));
m_tb->genDecRef(src);
} else if (fromType.isBool()) {
push(m_tb->gen(ConvBoolToStr, src));
} else if (fromType.isDbl()) {
push(m_tb->gen(ConvDblToStr, src));
} else if (fromType.isInt()) {
push(m_tb->gen(ConvIntToStr, src));
} else if (fromType.isObj()) {
spillStack(); // may throw
push(m_tb->gen(ConvObjToStr, src));
} else {
// for int to string conversion, this calls a helper that returns
// a string with ref count of 0.
pushIncRef(m_tb->genConvToStr(src));
spillStack(); // may throw
push(m_tb->gen(ConvCellToStr, src));
}
m_tb->genDecRef(src);
}
void HhbcTranslator::emitCastObject() {
emitInterpOneOrPunt(Type::Obj, 1);
}
static
@@ -2538,7 +2553,7 @@ void HhbcTranslator::emitMod() {
m_stackDeficit,
exitSpillValues,
[&](IRFactory* irf, Trace* t) {
// Dividing by zero. Interpreting will raise a notice and
// Dividing by zero. Interpreting will raise a notice and
// produce the boolean false. Punch out here and resume after
// the Mod instruction; this should be rare.
m_tb->genFor(t, RaiseWarning,
+7 -3
Ver Arquivo
@@ -466,12 +466,16 @@ bool IRInstruction::killsSource(int idx) const {
switch (m_op) {
case DecRef:
case ConvObjToArr:
case ConvGenToArr:
case ConvCellToArr:
case ConvCellToBool:
case ConvObjToDbl:
case ConvStrToDbl:
case ConvGenToDbl:
case ConvCellToDbl:
case ConvObjToInt:
case ConvGenToInt:
case ConvCellToInt:
case ConvCellToObj:
case ConvObjToStr:
case ConvCellToStr:
assert(idx == 0);
return true;
case ArraySet:
+24 -14
Ver Arquivo
@@ -175,27 +175,35 @@ O(ConvDblToArr, D(Arr), S(Dbl), C|N) \
O(ConvIntToArr, D(Arr), S(Int), C|N) \
O(ConvObjToArr, D(Arr), S(Obj), N|CRc|K) \
O(ConvStrToArr, D(Arr), S(Str), N|CRc) \
O(ConvGenToArr, D(Arr), S(Gen), N|CRc|K) \
O(ConvCellToArr, D(Arr), S(Cell), N|CRc|K) \
\
O(ConvToBool, D(Bool), S(Gen), C|N) \
O(ConvArrToBool, D(Bool), S(Arr), C|N) \
O(ConvDblToBool, D(Bool), S(Dbl), C) \
O(ConvIntToBool, D(Bool), S(Int), C) \
O(ConvStrToBool, D(Bool), S(Str), N) \
O(ConvCellToBool, D(Bool), S(Cell), N) \
\
O(ConvArrToDbl, D(Dbl), S(Arr), N) \
O(ConvArrToDbl, D(Dbl), S(Arr), C|N) \
O(ConvBoolToDbl, D(Dbl), S(Bool), C|Rm) \
O(ConvIntToDbl, D(Dbl), S(Int), C|Rm) \
O(ConvObjToDbl, D(Dbl), S(Obj), N|Er|CRc|K) \
O(ConvStrToDbl, D(Dbl), S(Str), N|CRc|K) \
O(ConvGenToDbl, D(Dbl), S(Gen), N|Er|CRc|K) \
O(ConvCellToDbl, D(Dbl), S(Cell), N|Er|CRc|K) \
\
O(ConvArrToInt, D(Int), S(Arr), N) \
O(ConvArrToInt, D(Int), S(Arr), C|N) \
O(ConvBoolToInt, D(Int), S(Bool), C|Rm) \
O(ConvDblToInt, D(Int), S(Dbl), C|N|Rm) \
O(ConvObjToInt, D(Int), S(Obj), N|Er|CRc|K) \
O(ConvStrToInt, D(Int), S(Str), N) \
O(ConvGenToInt, D(Int), S(Gen), N|Er|CRc|K) \
O(ConvCellToInt, D(Int), S(Cell), N|Er|CRc|K) \
\
O(ConvToObj, D(Obj), S(Gen), C|N) \
O(ConvCellToObj, D(Obj), S(Cell), N|CRc|K) \
\
O(ConvToStr, D(Str), S(Gen), C|N) \
O(ConvBoolToStr, D(StaticStr), S(Bool), C|Rm) \
O(ConvDblToStr, D(Str), S(Dbl), N) \
O(ConvIntToStr, D(Str), S(Int), N) \
O(ConvObjToStr, D(Str), S(Obj), N|Er|CRc|K) \
O(ConvCellToStr, D(Str), S(Cell), N|Er|CRc|K) \
\
O(ExtendsClass, D(Bool), S(Cls) C(Cls), C) \
O(IsTypeMem, D(Bool), S(PtrToGen), NA) \
@@ -2384,13 +2392,15 @@ int32_t spillValueCells(IRInstruction* spillStack);
constexpr int kSpillStackActRecExtraArgs = 5;
inline bool isConvIntOrPtrToBool(IRInstruction* instr) {
if (instr->getOpcode() != ConvToBool) {
return false;
switch (instr->getOpcode()) {
case ConvIntToBool:
return true;
case ConvCellToBool:
return instr->getSrc(0)->getType().subtypeOfAny(
Type::Func, Type::Cls, Type::FuncCls, Type::VarEnv, Type::TCA);
default:
return false;
}
return instr->getSrc(0)->isA(
Type::Int | Type::Func | Type::Cls | Type::FuncCls |
Type::VarEnv | Type::TCA);
}
/*
@@ -649,51 +649,6 @@ void LinearScan::computePreColoringHint() {
m_preColoringHint.add(inst->getSrc(0), 0, 1);
}
break;
case ConvBoolToArr:
case ConvDblToArr:
case ConvIntToArr:
case ConvObjToArr:
case ConvStrToArr:
case ConvGenToArr:
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);
} else if (fromType == Type::Str ||
fromType == Type::StaticStr ||
fromType.isArray() ||
fromType == Type::Obj) {
m_preColoringHint.add(src, 0, 0);
}
break;
}
case ConvArrToDbl:
case ConvBoolToDbl:
case ConvIntToDbl:
case ConvObjToDbl:
case ConvStrToDbl:
case ConvGenToDbl:
break;
case ConvBoolToInt:
case ConvDblToInt:
case ConvObjToInt:
break;
case ConvStrToInt:
{
SSATmp* src = inst->getSrc(0);
m_preColoringHint.add(src, 0, 0);
break;
}
case ConvGenToInt:
break;
case ConvToObj:
break;
case ConvToStr:
break;
case InstanceOf:
case NInstanceOf:
case JmpInstanceOf:
@@ -64,6 +64,58 @@ static const DestType DNone = DestType::None;
*/
static CallMap s_callMap({
/* Opcode, Func, Dest, SyncPoint, Args */
{ConvBoolToArr, (TCA)convCellToArrHelper, DSSA, SNone,
{{TV, 0}}},
{ConvDblToArr, (TCA)convCellToArrHelper, DSSA, SNone,
{{TV, 0}}},
{ConvIntToArr, (TCA)convCellToArrHelper, DSSA, SNone,
{{TV, 0}}},
{ConvObjToArr, (TCA)convCellToArrHelper, DSSA, SNone,
{{TV, 0}}},
{ConvStrToArr, (TCA)convCellToArrHelper, DSSA, SNone,
{{TV, 0}}},
{ConvCellToArr, (TCA)convCellToArrHelper, DSSA, SNone,
{{TV, 0}}},
{ConvArrToBool, (TCA)convArrToBoolHelper, DSSA, SNone,
{{SSA, 0}}},
{ConvStrToBool, (TCA)convStrToBoolHelper, DSSA, SNone,
{{SSA, 0}}},
{ConvCellToBool, (TCA)convCellToBoolHelper, DSSA, SNone,
{{TV, 0}}},
{ConvArrToDbl, (TCA)convArrToDblHelper, DSSA, SNone,
{{SSA, 0}}},
{ConvObjToDbl, (TCA)convCellToDblHelper, DSSA, SSync,
{{TV, 0}}},
{ConvStrToDbl, (TCA)convStrToDblHelper, DSSA, SSync,
{{SSA, 0}}},
{ConvCellToDbl, (TCA)convCellToDblHelper, DSSA, SSync,
{{TV, 0}}},
{ConvArrToInt, (TCA)convArrToIntHelper, DSSA, SNone,
{{SSA, 0}}},
{ConvDblToInt, (TCA)convDblToIntHelper, DSSA, SNone,
{{SSA, 0}}},
{ConvObjToInt, (TCA)convCellToIntHelper, DSSA, SSync,
{{TV, 0}}},
{ConvStrToInt, (TCA)convStrToIntHelper, DSSA, SNone,
{{SSA, 0}}},
{ConvCellToInt, (TCA)convCellToIntHelper, DSSA, SSync,
{{TV, 0}}},
{ConvCellToObj, (TCA)convCellToObjHelper, DSSA, SSync,
{{TV, 0}}},
{ConvDblToStr, (TCA)convDblToStrHelper, DSSA, SNone,
{{SSA, 0}}},
{ConvIntToStr, (TCA)convIntToStrHelper, DSSA, SNone,
{{SSA, 0}}},
{ConvObjToStr, (TCA)convObjToStrHelper, DSSA, SSync,
{{SSA, 0}}},
{ConvCellToStr, (TCA)convCellToStrHelper, DSSA, SSync,
{{TV, 0}}},
{AddElemStrKey, (TCA)addElemStringKeyHelper, DSSA, SNone,
{{SSA, 0}, {SSA, 1}, {TV, 2}}},
{AddElemIntKey, (TCA)addElemIntKeyHelper, DSSA, SNone,
+59 -58
Ver Arquivo
@@ -100,7 +100,10 @@ SSATmp* Simplifier::simplify(IRInstruction* inst) {
case ConvDblToArr: return simplifyConvToArr(inst);
case ConvIntToArr: return simplifyConvToArr(inst);
case ConvStrToArr: return simplifyConvToArr(inst);
case ConvToBool: return simplifyConvToBool(inst);
case ConvArrToBool: return simplifyConvArrToBool(inst);
case ConvDblToBool: return simplifyConvDblToBool(inst);
case ConvIntToBool: return simplifyConvIntToBool(inst);
case ConvStrToBool: return simplifyConvStrToBool(inst);
case ConvArrToDbl: return simplifyConvArrToDbl(inst);
case ConvBoolToDbl: return simplifyConvBoolToDbl(inst);
case ConvIntToDbl: return simplifyConvIntToDbl(inst);
@@ -109,8 +112,9 @@ SSATmp* Simplifier::simplify(IRInstruction* inst) {
case ConvBoolToInt: return simplifyConvBoolToInt(inst);
case ConvDblToInt: return simplifyConvDblToInt(inst);
case ConvStrToInt: return simplifyConvStrToInt(inst);
case ConvToObj: return simplifyConvToObj(inst);
case ConvToStr: return simplifyConvToStr(inst);
case ConvBoolToStr: return simplifyConvBoolToStr(inst);
case ConvDblToStr: return simplifyConvDblToStr(inst);
case ConvIntToStr: return simplifyConvIntToStr(inst);
case Unbox: return simplifyUnbox(inst);
case UnboxPtr: return simplifyUnboxPtr(inst);
case IsType:
@@ -396,7 +400,10 @@ SSATmp* Simplifier::simplifyNot(SSATmp* src) {
// TODO: Add more algebraic simplification rules for NOT
switch (op) {
case ConvToBool:
case ConvArrToBool:
case ConvDblToBool:
case ConvIntToBool:
case ConvStrToBool:
return simplifyNot(inst->getSrc(0));
case OpXor: {
// !!X --> bool(X)
@@ -1069,34 +1076,40 @@ SSATmp* Simplifier::simplifyConvToArr(IRInstruction* inst) {
return nullptr;
}
SSATmp* Simplifier::simplifyConvToBool(IRInstruction* inst) {
SSATmp* Simplifier::simplifyConvArrToBool(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) {
if (src->isConst()) {
if (src->getValArr()->empty()) {
return genDefBool(false);
}
return genDefBool(true);
}
return nullptr;
}
SSATmp* Simplifier::simplifyConvDblToBool(IRInstruction* inst) {
SSATmp* src = inst->getSrc(0);
if (src->isConst()) {
if (srcType == Type::Int) {
return genDefBool(bool(src->getValInt()));
}
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);
}
return genDefBool(bool(src->getValDbl()));
}
return nullptr;
}
SSATmp* Simplifier::simplifyConvIntToBool(IRInstruction* inst) {
SSATmp* src = inst->getSrc(0);
if (src->isConst()) {
return genDefBool(bool(src->getValInt()));
}
return nullptr;
}
SSATmp* Simplifier::simplifyConvStrToBool(IRInstruction* inst) {
SSATmp* src = inst->getSrc(0);
if (src->isConst()) {
// 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());
}
return nullptr;
}
@@ -1178,43 +1191,31 @@ SSATmp* Simplifier::simplifyConvStrToInt(IRInstruction* inst) {
return nullptr;
}
SSATmp* Simplifier::simplifyConvToObj(IRInstruction* inst) {
SSATmp* Simplifier::simplifyConvBoolToStr(IRInstruction* inst) {
SSATmp* src = inst->getSrc(0);
Type srcType = src->getType();
if (srcType == Type::Obj) {
return src;
if (src->isConst()) {
if (src->getValBool()) {
return m_tb->genDefConst(StringData::GetStaticString("1"));
}
return m_tb->genDefConst(StringData::GetStaticString(""));
}
return nullptr;
}
SSATmp* Simplifier::simplifyConvToStr(IRInstruction* inst) {
SSATmp* Simplifier::simplifyConvDblToStr(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 (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 m_tb->genDefConst(
StringData::convert_double_helper(src->getValDbl()));
}
return nullptr;
}
SSATmp* Simplifier::simplifyConvIntToStr(IRInstruction* inst) {
SSATmp* src = inst->getSrc(0);
if (src->isConst()) {
return m_tb->genDefConst(
StringData::convert_integer_helper(src->getValInt()));
}
return nullptr;
}
+8 -3
Ver Arquivo
@@ -63,7 +63,11 @@ private:
SSATmp* simplifyJmpIsType(IRInstruction*);
SSATmp* simplifyConcat(SSATmp* src1, SSATmp* src2);
SSATmp* simplifyConvToArr(IRInstruction*);
SSATmp* simplifyConvToBool(IRInstruction*);
SSATmp* simplifyConvArrToBool(IRInstruction*);
SSATmp* simplifyConvDblToBool(IRInstruction*);
SSATmp* simplifyConvIntToBool(IRInstruction*);
SSATmp* simplifyConvStrToBool(IRInstruction*);
SSATmp* simplifyConvToDbl(IRInstruction*);
SSATmp* simplifyConvArrToDbl(IRInstruction*);
SSATmp* simplifyConvBoolToDbl(IRInstruction*);
SSATmp* simplifyConvIntToDbl(IRInstruction*);
@@ -73,8 +77,9 @@ private:
SSATmp* simplifyConvDblToInt(IRInstruction*);
SSATmp* simplifyConvObjToInt(IRInstruction*);
SSATmp* simplifyConvStrToInt(IRInstruction*);
SSATmp* simplifyConvToObj(IRInstruction*);
SSATmp* simplifyConvToStr(IRInstruction*);
SSATmp* simplifyConvBoolToStr(IRInstruction*);
SSATmp* simplifyConvDblToStr(IRInstruction*);
SSATmp* simplifyConvIntToStr(IRInstruction*);
SSATmp* simplifyUnbox(IRInstruction*);
SSATmp* simplifyUnboxPtr(IRInstruction*);
SSATmp* simplifyCheckInit(IRInstruction* inst);
+19 -14
Ver Arquivo
@@ -396,21 +396,26 @@ SSATmp* TraceBuilder::genDefNone() {
return gen(DefConst, Type::None, &cdata);
}
SSATmp* TraceBuilder::genConvToStr(SSATmp* src) {
if (src->getType() == Type::Bool) {
// Bool to string code sequence loads static strings
return gen(ConvToStr, Type::StaticStr, src);
} else {
return gen(ConvToStr, Type::Str, src);
}
}
SSATmp* TraceBuilder::genConvToObj(SSATmp* src) {
return gen(ConvToObj, Type::Obj, src);
}
SSATmp* TraceBuilder::genConvToBool(SSATmp* src) {
return gen(ConvToBool, Type::Bool, src);
Type fromType = src->getType();
if (fromType.isBool()) {
return src;
} else if (fromType.isNull()) {
return genDefConst(false);
} else if (fromType.isArray()) {
return gen(ConvArrToBool, src);
} else if (fromType.isDbl()) {
return gen(ConvDblToBool, src);
} else if (fromType.isInt()) {
return gen(ConvIntToBool, src);
} else if (fromType.isString()) {
return gen(ConvStrToBool, src);
} else if (fromType.isObj()) {
// If a value is known to be an object, it is known to be non null.
return genDefConst(true);
} else {
return gen(ConvCellToBool, src);
}
}
SSATmp* TraceBuilder::genCmp(Opcode opc, SSATmp* src1, SSATmp* src2) {
@@ -187,10 +187,6 @@ public:
SSATmp* genCmp(Opcode opc, SSATmp* src1, SSATmp* src2);
SSATmp* genCastStk(uint32_t id, Type type);
SSATmp* genConvToBool(SSATmp* src);
SSATmp* genConvToDbl(SSATmp* src);
SSATmp* genConvToStr(SSATmp* src);
SSATmp* genConvToArr(SSATmp* src);
SSATmp* genConvToObj(SSATmp* src);
SSATmp* genLdPropAddr(SSATmp* obj, SSATmp* prop);
SSATmp* genLdClsMethod(SSATmp* cls, uint32_t methodSlot);
SSATmp* genLdClsMethodCache(SSATmp* className,
@@ -53,6 +53,134 @@ HOT_FUNC_VM RefData* box_value(TypedValue tv) {
return tvBoxHelper(tv.m_type, tv.m_data.num);
}
ArrayData* convCellToArrHelper(TypedValue tv) {
// Note: the call sites of this function all assume that
// no user code will run and no recoverable exceptions will
// occur while running this code. This seems trivially true
// in all cases but converting objects to arrays. It also
// seems true for that case as well, since the resulting array
// is essentially metadata for the object. If that is not true,
// you might end up looking at this code in a debugger and now
// you know why.
tvCastToArrayInPlace(&tv); // consumes a ref on counted values
return tv.m_data.parr;
}
int64_t convArrToBoolHelper(const ArrayData* a) {
return a->size() != 0;
}
int64_t convStrToBoolHelper(const StringData* s) {
return s->toBoolean();
}
int64_t convCellToBoolHelper(TypedValue tv) {
// Cannot call tvCastToBooleanInPlace here because some of the
// call sites will not be increasing the ref count on tv before
// calling, the ref count must be left alone.
switch (tv.m_type) {
case KindOfUninit:
case KindOfNull: return false;
case KindOfBoolean: return tv.m_data.num;
case KindOfInt64: return tv.m_data.num != 0;
case KindOfDouble: return tv.m_data.dbl != 0;
case KindOfStaticString:
case KindOfString: return tv.m_data.pstr->toBoolean();
case KindOfArray: return !tv.m_data.parr->empty();
case KindOfObject: return tv.m_data.pobj != nullptr;
default: not_reached();
}
}
int64_t convArrToDblHelper(ArrayData* a) {
return reinterpretDblAsInt(a->empty() ? 0 : 1);
}
int64_t convStrToDblHelper(const StringData* s) {
return reinterpretDblAsInt(s->toDouble());
}
int64_t convCellToDblHelper(TypedValue tv) {
tvCastToDoubleInPlace(&tv); // consumes a ref on counted values
// but not if an exception happens. (REVIEW)
return tv.m_data.num;
}
int64_t convArrToIntHelper(ArrayData* a) {
return a->empty() ? 0 : 1;
}
int64_t convDblToIntHelper(int64_t i) {
double d = reinterpretIntAsDbl(i);
return (d >= 0 ? d > std::numeric_limits<uint64_t>::max() ? 0u :
(uint64_t)d : (int64_t)d);
}
int64_t convStrToIntHelper(const StringData* s) {
return s->toInt64(10);
}
int64_t convCellToIntHelper(TypedValue tv) {
tvCastToInt64InPlace(&tv); // consumes a ref on counted values
// but not if an exception happens. (REVIEW)
return tv.m_data.num;
}
ObjectData* convCellToObjHelper(TypedValue tv) {
// Note: the call sites of this function all assume that
// no user code will run and no recoverable exceptions will
// occur while running this code. This seems trivially true
// in all cases but converting arrays to objects. It also
// seems true for that case as well, since the source array
// is essentially metadata for the object. If that is not true,
// you might end up looking at this code in a debugger and now
// you know why.
tvCastToObjectInPlace(&tv); // consumes a ref on counted values
return tv.m_data.pobj;
}
StringData* convDblToStrHelper(int64_t i) {
double d = reinterpretIntAsDbl(i);
auto r = buildStringData(d);
r->incRefCount();
return r;
}
StringData* convIntToStrHelper(int64_t i) {
auto r = buildStringData(i);
r->incRefCount();
return r;
}
StringData* convObjToStrHelper(ObjectData* o) {
try {
auto s = o->t___tostring();
auto r = s.get();
o->decRefCount();
if (!r->isStatic()) r->incRefCount();
return r;
} catch (...) {
o->decRefCount();
throw;
}
}
StringData* convCellToStrHelper(TypedValue tv) {
switch (tv.m_type) {
case KindOfUninit:
case KindOfNull: return buildStringData("");
case KindOfBoolean: return buildStringData(tv.m_data.num ? "1" : "");
case KindOfInt64: return convIntToStrHelper(tv.m_data.num);
case KindOfDouble: return convDblToStrHelper(tv.m_data.num);
case KindOfStaticString:
case KindOfString: return tv.m_data.pstr;
case KindOfArray: tvDecRefArr(&tv); return buildStringData("Array");
case KindOfObject: return convObjToStrHelper(tv.m_data.pobj);
default: not_reached();
}
}
void raisePropertyOnNonObject() {
raise_warning("Cannot access property on non-object");
}
@@ -57,6 +57,45 @@ ArrayData* addElemStringKeyHelper(ArrayData* ad, StringData* key,
TypedValue setNewElem(TypedValue* base, Cell val);
void bindNewElemIR(TypedValue* base, RefData* val, MInstrState* mis);
RefData* box_value(TypedValue tv);
ArrayData* convCellToArrHelper(TypedValue tv);
/* Helper functions for conversion instructions that are too
complicated to inline */
inline int64_t reinterpretDblAsInt(double d) {
union {
int64_t intval;
double dblval;
} u;
u.dblval = d;
return u.intval;
}
inline double reinterpretIntAsDbl(int64_t i) {
union {
int64_t intval;
double dblval;
} u;
u.intval = i;
return u.dblval;
}
int64_t convArrToBoolHelper(const ArrayData* a);
int64_t convStrToBoolHelper(const StringData* s);
int64_t convCellToBoolHelper(TypedValue tv);
int64_t convArrToDblHelper(ArrayData* a);
int64_t convStrToDblHelper(const StringData* s);
int64_t convCellToDblHelper(TypedValue tv);
int64_t convArrToIntHelper(ArrayData* a);
int64_t convDblToIntHelper(int64_t i);
int64_t convStrToIntHelper(const StringData* s);
int64_t convCellToIntHelper(TypedValue tv);
ObjectData* convCellToObjHelper(TypedValue tv);
StringData* convDblToStrHelper(int64_t i);
StringData* convIntToStrHelper(int64_t i);
StringData* convObjToStrHelper(ObjectData* o);
StringData* convCellToStrHelper(TypedValue tv);
void raisePropertyOnNonObject();
void raiseUndefProp(ObjectData* base, const StringData* name);
void VerifyParamTypeFail(int param);