Fastpath for simple array IssetM

TranslatorX64 has a fast path for this case so I thought I'd
try it out in the ir. It's a small but apparently real win in Perflab.
Esse commit está contido em:
bsimmers
2013-03-25 15:03:12 -07:00
commit de Sara Golemon
commit 3ec24e45d6
5 arquivos alterados com 94 adições e 24 exclusões
@@ -367,6 +367,7 @@ CALL_STK_OPCODE(SetOpElem)
CALL_STK_OPCODE(IncDecElem)
CALL_STK_OPCODE(SetNewElem)
CALL_STK_OPCODE(BindNewElem)
CALL_OPCODE(ArrayIsset)
CALL_OPCODE(IssetElem)
CALL_OPCODE(EmptyElem)
@@ -431,8 +431,9 @@ private:
void emitSetOpNewElem();
void emitIncDecNewElem();
void emitBindNewElem();
void emitSimpleArraySet(SSATmp* key, SSATmp* value);
void emitSimpleArrayGet(SSATmp* key);
void emitArraySet(SSATmp* key, SSATmp* value);
void emitArrayGet(SSATmp* key);
void emitArrayIsset();
void checkStrictlyInteger(SSATmp*& key, KeyType& keyType,
bool& checkForInt);
+3
Ver Arquivo
@@ -487,6 +487,9 @@ O_STK(SetNewElem, DVector, S(PtrToGen) \
O_STK(BindNewElem, ND, S(PtrToGen) \
S(BoxedCell) \
S(PtrToCell),VElem|E|N|Mem|Refs|Er) \
O(ArrayIsset, D(Bool), C(TCA) \
S(Arr) \
S(Int,Str), E|N|Mem|Refs|Er) \
O(IssetElem, D(Bool), C(TCA) \
S(PtrToGen) \
S(Gen) \
+8 -7
Ver Arquivo
@@ -111,13 +111,13 @@ static CallMap s_callMap({
{{SSA, 1}, {SSA, 2}, {VecKeyS, 3}, {SSA, 4}, {SSA, 5}}},
{SetProp, {FSSA, 0}, DTV, SSync,
{{SSA, 1}, {SSA, 2}, {VecKeyS, 3}, {TV, 4}}},
{SetOpProp,{FSSA, 0}, DTV, SSync,
{SetOpProp, {FSSA, 0}, DTV, SSync,
{{SSA, 1}, {VecKeyS, 2}, {TV, 3}, {SSA, 4}}},
{IncDecProp,{FSSA, 0}, DTV, SSync,
{IncDecProp, {FSSA, 0}, DTV, SSync,
{{SSA, 1}, {SSA, 2}, {VecKeyS, 3}, {SSA, 4}}},
{EmptyProp,{FSSA, 0}, DSSA, SSync,
{EmptyProp, {FSSA, 0}, DSSA, SSync,
{{SSA, 1}, {SSA, 2}, {VecKeyS, 3}}},
{IssetProp,{FSSA, 0}, DSSA, SSync,
{IssetProp, {FSSA, 0}, DSSA, SSync,
{{SSA, 1}, {SSA, 2}, {VecKeyS, 3}}},
{ElemX, {FSSA, 0}, DSSA, SSync,
{{SSA, 1}, {VecKeyIS, 2}, {SSA, 3}}},
@@ -137,14 +137,15 @@ static CallMap s_callMap({
{{SSA, 1}, {SSA, 2}, {TV, 3}, {SSA, 4}}},
{SetElem, {FSSA, 0}, DTV, SSync,
{{SSA, 1}, {VecKeyIS, 2}, {TV, 3}}},
{SetOpElem,{FSSA, 0}, DTV, SSync,
{SetOpElem, {FSSA, 0}, DTV, SSync,
{{SSA, 1}, {VecKeyIS, 2}, {TV, 3}, {SSA, 4}}},
{IncDecElem,{FSSA, 0}, DTV, SSync,
{IncDecElem, {FSSA, 0}, DTV, SSync,
{{SSA, 1}, {VecKeyIS, 2}, {SSA, 3}}},
{SetNewElem, (TCA)setNewElem, DTV, SSync, {{SSA, 0}, {TV, 1}}},
{BindNewElem, (TCA)bindNewElemIR, DNone, SSync,
{{SSA, 0}, {SSA, 1}, {SSA, 2}}},
{IssetElem,{FSSA, 0}, DSSA, SSync,
{ArrayIsset, {FSSA, 0}, DSSA, SSync, {{SSA, 1}, {SSA, 2}}},
{IssetElem, {FSSA, 0}, DSSA, SSync,
{{SSA, 1}, {VecKeyIS, 2}, {SSA, 3}}},
{EmptyElem,{FSSA, 0}, DSSA, SSync,
{{SSA, 1}, {VecKeyIS, 2}, {SSA, 3}}},
@@ -285,6 +285,7 @@ void HhbcTranslator::VectorTranslator::checkMIState() {
Type baseType = Type::fromRuntimeType(baseRtt);
const bool isCGetM = m_ni.mInstrOp() == OpCGetM;
const bool isSetM = m_ni.mInstrOp() == OpSetM;
const bool isIssetM = m_ni.mInstrOp() == OpIssetM;
const bool isSingle = m_ni.immVecM.size() == 1;
assert(baseType.isBoxed() || baseType.notBoxed());
@@ -300,16 +301,22 @@ void HhbcTranslator::VectorTranslator::checkMIState() {
// Array access with one element in the vector
const bool singleElem = isSingle && mcodeMaybeArrayKey(m_ni.immVecM[0]);
// SetM on an array with one vector element
// SetM with one vector array element
const bool simpleArraySet = isSetM && singleElem;
// IssetM with one vector array element and an Arr base
const bool simpleArrayIsset = isIssetM && singleElem &&
baseType.subtypeOf(Type::Arr);
// CGetM on an array with a base that won't use MInstrState. Str
// will use tvScratch and baseStrOff and Obj will fatal or use
// tvRef.
const bool simpleArrayGet = isCGetM && singleElem &&
baseType.not(Type::Str | Type::Obj);
if (simpleProp || singlePropSet || simpleArraySet || simpleArrayGet) {
if (simpleProp || singlePropSet ||
simpleArraySet || simpleArrayGet ||
simpleArrayIsset) {
setNoMIState();
}
}
@@ -475,7 +482,7 @@ void HhbcTranslator::VectorTranslator::emitBaseLCR() {
bool HhbcTranslator::VectorTranslator::isSimpleArrayOp() {
SSATmp* base = getInput(m_mii.valCount());
VM::Op op = m_ni.mInstrOp();
if ((op == OpSetM || op == OpCGetM) &&
if ((op == OpSetM || op == OpCGetM || op == OpIssetM) &&
isSimpleBase() &&
isSingleMember() &&
mcodeMaybeArrayKey(m_ni.immVecM[0]) &&
@@ -1118,7 +1125,7 @@ static inline bool issetEmptyPropImpl(Class* ctx, TypedValue* base,
#define ISSET(nm, hot, ...) \
hot \
/* This returns int64_t to ensure all 64 bits of rax are valid */ \
int64_t nm(Class* ctx, TypedValue* base, TypedValue key) { \
uint64_t nm(Class* ctx, TypedValue* base, TypedValue key) { \
return issetEmptyPropImpl<__VA_ARGS__>(ctx, base, key); \
}
namespace VectorHelpers {
@@ -1128,7 +1135,7 @@ HELPER_TABLE(ISSET)
void HhbcTranslator::VectorTranslator::emitIssetEmptyProp(bool isEmpty) {
SSATmp* key = getInput(m_iInd);
typedef bool (*OpFunc)(Class*, TypedValue*, TypedValue);
typedef uint64_t (*OpFunc)(Class*, TypedValue*, TypedValue);
BUILD_OPTAB_HOT(getKeyTypeS(key), key->isBoxed(), isEmpty,
m_base->isA(Type::Obj));
m_ht.spillStack();
@@ -1371,20 +1378,20 @@ void HhbcTranslator::VectorTranslator::checkStrictlyInteger(
}
}
static inline TypedValue* checkedGet(ArrayData* a, StringData* key) {
static inline TypedValue* checkedGetCell(ArrayData* a, StringData* key) {
int64_t i;
return UNLIKELY(key->isStrictlyInteger(i)) ? a->nvGetCell(i)
: a->nvGetCell(key);
}
static inline TypedValue* checkedGet(ArrayData* a, int64_t key) {
static inline TypedValue* checkedGetCell(ArrayData* a, int64_t key) {
not_reached();
}
template<KeyType keyType, bool checkForInt>
static inline TypedValue arrayGetImpl(
ArrayData* a, typename KeyTypeTraits<keyType>::rawType key) {
TypedValue* ret = checkForInt ? checkedGet(a, key)
TypedValue* ret = checkForInt ? checkedGetCell(a, key)
: a->nvGetCell(key);
tvRefcountedIncRef(ret);
return *ret;
@@ -1406,7 +1413,7 @@ HELPER_TABLE(ELEM)
}
#undef ELEM
void HhbcTranslator::VectorTranslator::emitSimpleArrayGet(SSATmp* key) {
void HhbcTranslator::VectorTranslator::emitArrayGet(SSATmp* key) {
KeyType keyType;
bool checkForInt;
checkStrictlyInteger(key, keyType, checkForInt);
@@ -1458,7 +1465,7 @@ void HhbcTranslator::VectorTranslator::emitCGetElem() {
SSATmp* key = getInput(m_iInd);
if (isSimpleArrayOp()) {
emitSimpleArrayGet(key);
emitArrayGet(key);
return;
}
@@ -1524,8 +1531,12 @@ static inline bool issetEmptyElemImpl(TypedValue* base, TypedValue keyVal,
MInstrState* mis) {
TypedValue* key = keyPtr<keyType>(keyVal);
key = unbox<keyType, unboxKey>(key);
return HPHP::VM::IssetEmptyElem<isEmpty, false, keyType>(
mis->tvScratch, mis->tvRef, base, mis->baseStrOff, key);
// mis == nullptr if we proved that it won't be used. mis->tvScratch and
// mis->tvRef are ok because those params are passed by
// reference. mis->baseStrOff is passed by value so we have to check mis
// before accessing it.
return VM::IssetEmptyElem<isEmpty, false, keyType>(
mis->tvScratch, mis->tvRef, base, mis ? mis->baseStrOff : false, key);
}
#define HELPER_TABLE(m) \
@@ -1564,7 +1575,60 @@ void HhbcTranslator::VectorTranslator::emitIssetEmptyElem(bool isEmpty) {
}
#undef HELPER_TABLE
static inline TypedValue* checkedGet(ArrayData* a, StringData* key) {
int64_t i;
return UNLIKELY(key->isStrictlyInteger(i)) ? a->nvGet(i)
: a->nvGet(key);
}
static inline TypedValue* checkedGet(ArrayData* a, int64_t key) {
not_reached();
}
template<KeyType keyType, bool checkForInt>
static inline uint64_t arrayIssetImpl(
ArrayData* a, typename KeyTypeTraits<keyType>::rawType key) {
TypedValue* value = checkForInt ? checkedGet(a, key)
: a->nvGet(key);
Variant* var = &tvAsVariant(value);
return var && !var->isNull();
}
#define HELPER_TABLE(m) \
/* name keyType checkForInt */ \
m(arrayIssetS, StrKey, false) \
m(arrayIssetSi, StrKey, true) \
m(arrayIssetI, IntKey, false)
#define ISSET(nm, keyType, checkForInt) \
uint64_t nm(ArrayData* a, TypedValue* key) { \
return arrayIssetImpl<keyType, checkForInt>(a, keyAsRaw<keyType>(key)); \
}
namespace VectorHelpers {
HELPER_TABLE(ISSET)
}
#undef ISSET
void HhbcTranslator::VectorTranslator::emitArrayIsset() {
SSATmp* key = getInput(m_iInd);
KeyType keyType;
bool checkForInt;
checkStrictlyInteger(key, keyType, checkForInt);
typedef uint64_t (*OpFunc)(ArrayData*, TypedValue*);
BUILD_OPTAB(keyType, checkForInt);
assert(m_base->isA(Type::Arr));
m_ht.spillStack();
m_result = m_tb.gen(ArrayIsset, cns((TCA)opFunc), m_base, key);
}
#undef HELPER_TABLE
void HhbcTranslator::VectorTranslator::emitIssetElem() {
if (isSimpleArrayOp()) {
emitArrayIsset();
return;
}
emitIssetEmptyElem(false);
}
@@ -1617,8 +1681,8 @@ HELPER_TABLE(ELEM)
}
#undef ELEM
void HhbcTranslator::VectorTranslator::emitSimpleArraySet(SSATmp* key,
SSATmp* value) {
void HhbcTranslator::VectorTranslator::emitArraySet(SSATmp* key,
SSATmp* value) {
assert(m_iInd == m_mii.valCount() + 1);
const int baseStkIdx = m_mii.valCount();
assert(key->getType().notBoxed());
@@ -1695,7 +1759,7 @@ void HhbcTranslator::VectorTranslator::emitSetElem() {
SSATmp* key = getInput(m_iInd);
if (isSimpleArrayOp()) {
emitSimpleArraySet(key, value);
emitArraySet(key, value);
return;
}