Remove genAssertStk/genCastStk and move their optimizations to Simplifier

The elimination of these is stateless, so it's going to
simplifier (along with getStackValue).  Other stack functions are
still here until I move EvalStack to tracebuilder.
Esse commit está contido em:
Jordan DeLong
2013-04-25 15:43:42 -07:00
commit de Sara Golemon
commit 1e1166d4d4
6 arquivos alterados com 208 adições e 191 exclusões
@@ -1825,8 +1825,12 @@ void HhbcTranslator::emitFCallBuiltin(uint32_t numArgs,
case KindOfArray:
case KindOfObject:
case KindOfString:
m_tb->genCastStk(numArgs - i - 1,
Type::fromDataType(pi.builtinType(), KindOfInvalid));
gen(
CastStk,
Type::fromDataType(pi.builtinType(), KindOfInvalid),
m_tb->getSp(),
cns(numArgs - i - 1)
);
break;
case KindOfDouble: not_reached();
case KindOfUnknown: break;
@@ -2185,7 +2189,7 @@ void HhbcTranslator::checkTypeTopOfStack(Type type,
void HhbcTranslator::assertTypeStack(uint32_t stackIndex, Type type) {
SSATmp* tmp = m_evalStack.top(stackIndex);
if (!tmp) {
m_tb->genAssertStk(stackIndex, type);
gen(AssertStk, type, m_tb->getSp(), cns(stackIndex));
return;
}
@@ -583,7 +583,7 @@ private:
* Eval stack helpers
*/
SSATmp* push(SSATmp* tmp);
SSATmp* pushIncRef(SSATmp* tmp) { return push(m_tb->gen(IncRef, tmp)); }
SSATmp* pushIncRef(SSATmp* tmp) { return push(gen(IncRef, tmp)); }
SSATmp* pop(Type type);
void popDecRef(Type type);
void discard(unsigned n);
+183 -3
Ver Arquivo
@@ -29,6 +29,152 @@ namespace JIT {
TRACE_SET_MOD(hhir);
//////////////////////////////////////////////////////////////////////
SSATmp* getStackValue(SSATmp* sp,
uint32_t index,
bool& spansCall,
Type& type) {
IRInstruction* inst = sp->inst();
switch (inst->op()) {
case DefSP:
return nullptr;
case ReDefGeneratorSP: {
auto srcInst = inst->getSrc(0)->inst();
assert(srcInst->op() == StashGeneratorSP);
return getStackValue(srcInst->getSrc(0), index, spansCall, type);
}
case ReDefSP:
return getStackValue(inst->getSrc(1), index, spansCall, type);
case ExceptionBarrier:
return getStackValue(inst->getSrc(0), index, spansCall, type);
case AssertStk:
// fallthrough
case CastStk:
// fallthrough
case GuardStk: {
// sp = GuardStk<T> sp, offset
// We don't have a value, but we may know the type due to guarding
// on it.
if (inst->getSrc(1)->getValInt() == index) {
type = inst->getTypeParam();
return nullptr;
}
return getStackValue(inst->getSrc(0),
index,
spansCall,
type);
}
case Call:
// sp = call(actrec, bcoffset, func, args...)
if (index == 0) {
// return value from call
return nullptr;
}
spansCall = true;
// search recursively on the actrec argument
return getStackValue(inst->getSrc(0), // sp = actrec argument to call
index -
(1 /* pushed */ - kNumActRecCells /* popped */),
spansCall,
type);
case SpillStack: {
int64_t numPushed = 0;
int32_t numSpillSrcs = inst->getNumSrcs() - 2;
for (int i = 0; i < numSpillSrcs; ++i) {
SSATmp* tmp = inst->getSrc(i + 2);
if (index == numPushed) {
if (tmp->inst()->op() == IncRef) {
tmp = tmp->inst()->getSrc(0);
}
type = tmp->type();
if (!type.equals(Type::None)) {
return tmp;
}
}
++numPushed;
}
// This is not one of the values pushed onto the stack by this
// spillstack instruction, so continue searching.
SSATmp* prevSp = inst->getSrc(0);
int64_t numPopped = inst->getSrc(1)->getValInt();
return getStackValue(prevSp,
// pop values pushed by spillstack
index - (numPushed - numPopped),
spansCall,
type);
}
case InterpOne: {
SSATmp* prevSp = inst->getSrc(1);
int64_t spAdjustment = inst->getSrc(3)->getValInt(); // # popped - # pushed
Type resultType = inst->getTypeParam();
if (index == 0 && resultType != Type::None) {
type = resultType;
return nullptr;
}
return getStackValue(prevSp, index + spAdjustment, spansCall, type);
}
case SpillFrame:
return getStackValue(inst->getSrc(0),
// pushes an ActRec
index - kNumActRecCells,
spansCall,
type);
case NewObj:
case NewObjCached:
if (index == kNumActRecCells) {
// newly allocated object, which we unfortunately don't have any
// kind of handle to :-(
type = Type::Obj;
return nullptr;
}
return getStackValue(sp->inst()->getSrc(2),
// NewObj pushes an object and an ActRec
index - (1 + kNumActRecCells),
spansCall,
type);
case NewObjNoCtorCached:
if (index == 0) {
type = Type::Obj;
return nullptr;
}
return getStackValue(sp->inst()->getSrc(1),
index - 1,
spansCall,
type);
default: {
SSATmp* value;
if (VectorEffects::getStackValue(sp->inst(), index,
value, type)) {
return value;
} else {
// If VectorEffects::getStackValue failed, it returns the next
// sp to search in value.
return getStackValue(value, index, spansCall, type);
}
}
}
// Should not get here!
not_reached();
}
//////////////////////////////////////////////////////////////////////
static void copyPropSrc(IRInstruction* inst, int index) {
auto tmp = inst->getSrc(index);
auto srcInst = tmp->inst();
@@ -170,14 +316,14 @@ SSATmp* Simplifier::simplify(IRInstruction* inst) {
case LdCls: return simplifyLdCls(inst);
case LdThis: return simplifyLdThis(inst);
case LdCtx: return simplifyLdCtx(inst);
case LdClsCtx: return simplifyLdClsCtx(inst);
case GetCtxFwdCall:return simplifyGetCtxFwdCall(inst);
case SpillStack: return simplifySpillStack(inst);
case Call: return simplifyCall(inst);
case CastStk: return simplifyCastStk(inst);
case AssertStk: return simplifyAssertStk(inst);
case ExitOnVarEnv: return simplifyExitOnVarEnv(inst);
default:
@@ -1435,4 +1581,38 @@ SSATmp* Simplifier::simplifyCondJmp(IRInstruction* inst) {
return nullptr;
}
}}} // namespace HPHP::VM::JIT
SSATmp* Simplifier::simplifyCastStk(IRInstruction* inst) {
bool spansCall = false;
Type knownType = Type::None;
getStackValue(inst->getSrc(0),
inst->getSrc(1)->getValInt(),
spansCall,
knownType);
if (knownType.subtypeOf(inst->getTypeParam())) {
// No need to cast---the type was as good or better.
inst->convertToNop();
}
return nullptr;
}
SSATmp* Simplifier::simplifyAssertStk(IRInstruction* inst) {
Type knownType = Type::None;
bool spansCall = false;
UNUSED SSATmp* tmp = getStackValue(inst->getSrc(0),
inst->getSrc(1)->getValInt(),
spansCall,
knownType);
// AssertStk indicated that we knew the type from static analysis,
// so this assert just double checks.
if (tmp) assert(tmp->isA(inst->getTypeParam()));
if (knownType.subtypeOf(inst->getTypeParam())) {
inst->convertToNop();
}
return nullptr;
}
//////////////////////////////////////////////////////////////////////
}}}
+16
Ver Arquivo
@@ -117,6 +117,8 @@ private:
SSATmp* simplifyCondJmp(IRInstruction*);
SSATmp* simplifyQueryJmp(IRInstruction*);
SSATmp* simplifyExitOnVarEnv(IRInstruction*);
SSATmp* simplifyCastStk(IRInstruction*);
SSATmp* simplifyAssertStk(IRInstruction*);
private: // tracebuilder forwarders
template<class... Args> SSATmp* cns(Args&&...);
@@ -128,6 +130,20 @@ private:
//////////////////////////////////////////////////////////////////////
/*
* Track down a value using the StkPtr chain.
*
* The spansCall parameter tracks whether the returned value's
* lifetime on the stack spans a call. This search bottoms out on
* hitting either the initial DefSP instruction (failure), or some
* instruction that produced a view of the stack with the requested
* value.
*/
SSATmp* getStackValue(SSATmp* stack,
uint32_t index,
bool& spansCall,
Type& type);
/*
* Propagate very simple copies on the given instruction.
* Specifically, Movs, and also IncRefs of non-refcounted types.
+1 -182
Ver Arquivo
@@ -437,186 +437,6 @@ SSATmp* TraceBuilder::genStLoc(uint32_t id,
return retVal;
}
/*
* Track down a value that was previously spilled onto the stack
* The spansCall parameter tracks whether the returned value's
* lifetime on the stack spans a call. This search bottoms out
* on hitting either a DefSP instruction (failure), a SpillStack
* instruction that has the spilled location, or a call that returns
* the value.
*/
static SSATmp* getStackValue(SSATmp* sp,
uint32_t index,
bool& spansCall,
Type& type) {
IRInstruction* inst = sp->inst();
switch (inst->op()) {
case DefSP:
return nullptr;
case ReDefGeneratorSP: {
auto srcInst = inst->getSrc(0)->inst();
assert(srcInst->op() == StashGeneratorSP);
return getStackValue(srcInst->getSrc(0), index, spansCall, type);
}
case ReDefSP:
return getStackValue(inst->getSrc(1), index, spansCall, type);
case ExceptionBarrier:
return getStackValue(inst->getSrc(0), index, spansCall, type);
case AssertStk:
// fallthrough
case CastStk:
// fallthrough
case GuardStk: {
// sp = GuardStk<T> sp, offset
// We don't have a value, but we may know the type due to guarding
// on it.
if (inst->getSrc(1)->getValInt() == index) {
type = inst->getTypeParam();
return nullptr;
}
return getStackValue(inst->getSrc(0),
index,
spansCall,
type);
}
case Call:
// sp = call(actrec, bcoffset, func, args...)
if (index == 0) {
// return value from call
return nullptr;
}
spansCall = true;
// search recursively on the actrec argument
return getStackValue(inst->getSrc(0), // sp = actrec argument to call
index -
(1 /* pushed */ - kNumActRecCells /* popped */),
spansCall,
type);
case SpillStack: {
int64_t numPushed = 0;
int32_t numSpillSrcs = inst->getNumSrcs() - 2;
for (int i = 0; i < numSpillSrcs; ++i) {
SSATmp* tmp = inst->getSrc(i + 2);
if (index == numPushed) {
if (tmp->inst()->op() == IncRef) {
tmp = tmp->inst()->getSrc(0);
}
type = tmp->type();
if (!type.equals(Type::None)) {
return tmp;
}
}
++numPushed;
}
// This is not one of the values pushed onto the stack by this
// spillstack instruction, so continue searching.
SSATmp* prevSp = inst->getSrc(0);
int64_t numPopped = inst->getSrc(1)->getValInt();
return getStackValue(prevSp,
// pop values pushed by spillstack
index - (numPushed - numPopped),
spansCall,
type);
}
case InterpOne: {
SSATmp* prevSp = inst->getSrc(1);
int64_t spAdjustment = inst->getSrc(3)->getValInt(); // # popped - # pushed
Type resultType = inst->getTypeParam();
if (index == 0 && resultType != Type::None) {
type = resultType;
return nullptr;
}
return getStackValue(prevSp, index + spAdjustment, spansCall, type);
}
case SpillFrame:
return getStackValue(inst->getSrc(0),
// pushes an ActRec
index - kNumActRecCells,
spansCall,
type);
case NewObj:
case NewObjCached:
if (index == kNumActRecCells) {
// newly allocated object, which we unfortunately don't have any
// kind of handle to :-(
type = Type::Obj;
return nullptr;
}
return getStackValue(sp->inst()->getSrc(2),
// NewObj pushes an object and an ActRec
index - (1 + kNumActRecCells),
spansCall,
type);
case NewObjNoCtorCached:
if (index == 0) {
type = Type::Obj;
return nullptr;
}
return getStackValue(sp->inst()->getSrc(1),
index - 1,
spansCall,
type);
default: {
SSATmp* value;
if (VectorEffects::getStackValue(sp->inst(), index,
value, type)) {
return value;
} else {
// If VectorEffects::getStackValue failed, it returns the next
// sp to search in value.
return getStackValue(value, index, spansCall, type);
}
}
}
// Should not get here!
not_reached();
}
void TraceBuilder::genAssertStk(uint32_t id, Type type) {
Type knownType = Type::None;
bool spansCall = false;
UNUSED SSATmp* tmp = getStackValue(m_spValue, id, spansCall, knownType);
// We may have found a value if there was an inlined call.
// AssertStk indicated that we knew the type from static analysis,
// so let's double check.
if (tmp) {
assert(tmp->isA(type));
}
if (knownType == Type::None || type.strictSubtypeOf(knownType)) {
gen(AssertStk, type, m_spValue, cns(id));
}
}
SSATmp* TraceBuilder::genCastStk(uint32_t id, Type type) {
bool spansCall = false;
Type knownType = Type::None;
getStackValue(m_spValue, id, spansCall, knownType);
if (knownType.subtypeOf(Type::None) || !knownType.subtypeOf(type)) {
SSATmp* off = cns(id);
gen(CastStk, m_spValue, off);
IRInstruction* inst = m_spValue->inst();
inst->setTypeParam(type);
}
return m_spValue;
}
SSATmp* TraceBuilder::genLdStackAddr(SSATmp* sp, int64_t index) {
Type type;
bool spansCall;
@@ -1118,11 +938,10 @@ SSATmp* TraceBuilder::preOptimizeAssertLoc(IRInstruction* inst) {
auto const prevType = getLocalType(locId);
auto const typeParam = inst->getTypeParam();
if (prevType != Type::None && !typeParam.strictSubtypeOf(prevType)) {
if (!prevType.equals(Type::None) && !typeParam.strictSubtypeOf(prevType)) {
assert(prevType.subtypeOf(typeParam));
inst->convertToNop();
}
return nullptr;
}
@@ -186,7 +186,6 @@ struct TraceBuilder {
//////////////////////////////////////////////////////////////////////
// stack
void genAssertStk(uint32_t id, Type type);
SSATmp* genSpillStack(uint32_t stackAdjustment,
uint32_t numOpnds,
SSATmp** opnds);
@@ -233,7 +232,6 @@ struct TraceBuilder {
// TODO(#2058865): we should have a real not opcode
SSATmp* genNot(SSATmp* src);
SSATmp* genCastStk(uint32_t id, Type type);
SSATmp* genConvToBool(SSATmp* src);
//////////////////////////////////////////////////////////////////////