Apply metadata to the ir in translateTracelet

In one of my pending region compiler diffs, I added code to forget the
values/types of locals after some FCalls (not doing so was wrong but we were
mostly getting away with it). This exposed an issue where the known type of a
local in the IR was less specific that what Translator::analyze was using. The
more specific type came from metadata on instructions after the FCall, so this
diff applies metadat to the IR before translating each instruction, using the
same code I wrote for the region compiler.

The changes to apply the metadata are pretty small; most of the
changes in this diffs are real bugs I found while attempting an
alternate solution.
Esse commit está contido em:
bsimmers
2013-07-22 18:40:08 -07:00
commit de Sara Golemon
commit 631438f0fb
8 arquivos alterados com 129 adições e 36 exclusões
+6
Ver Arquivo
@@ -358,6 +358,12 @@ struct InterpOneData : IRExtraData {
// Opcode, in case we need to fix the stack differently. Some byte-
// code instructions modify things below the top of the stack.
Op opcode;
std::string show() const {
return folly::format("{}: bcOff:{}, popped:{}, pushed:{}",
opcodeToName(opcode), bcOff, cellsPopped,
cellsPushed).str();
}
};
/*
+29 -8
Ver Arquivo
@@ -222,6 +222,7 @@ void HhbcTranslator::replace(uint32_t index, SSATmp* tmp) {
}
Type HhbcTranslator::topType(uint32_t idx) const {
FTRACE(5, "Asking for type of stack elem {}\n", idx);
if (idx < m_evalStack.size()) {
return m_evalStack.top(idx)->type();
} else {
@@ -3663,6 +3664,7 @@ Type HhbcTranslator::interpOutputType(const NormalizedInstruction& inst) const {
case OutClassRef: return Type::Cls;
case OutSetM: return Type::Cell; // Imprecise but we can translate
// all cases that matter.
case OutFPushCufSafe: return Type::None;
case OutNone: return Type::None;
}
@@ -3678,6 +3680,14 @@ void HhbcTranslator::interpOutputLocals(const NormalizedInstruction& inst) {
};
switch (inst.op()) {
case OpCreateCont: {
auto numLocals = curFunc()->numLocals();
for (unsigned i = 0; i < numLocals; ++i) {
gen(OverrideLoc, Type::Uninit, LocalId(i), m_tb->fp());
}
break;
}
case OpSetN:
case OpSetOpN:
case OpIncDecN:
@@ -3833,10 +3843,10 @@ std::string HhbcTranslator::showStack() const {
out << folly::format("+{:-^62}+\n", str);
};
const int32_t frameCells = curFunc()->numSlotsInFrame();
const int32_t frameCells =
curFunc()->isGenerator() ? 0 : curFunc()->numSlotsInFrame();
const int32_t stackDepth =
m_tb->spOffset() + m_evalStack.size() - m_stackDeficit -
(curFunc()->isGenerator() ? 0 : frameCells);
m_tb->spOffset() + m_evalStack.size() - m_stackDeficit - frameCells;
auto spOffset = stackDepth;
auto elem = [&](const std::string& str) {
out << folly::format("| {:<60} |\n",
@@ -3845,12 +3855,23 @@ std::string HhbcTranslator::showStack() const {
assert(spOffset > 0);
--spOffset;
};
auto fpiStack = m_fpiStack;
auto fpi = curFunc()->findFPI(bcOff());
auto checkFpi = [&]() {
if (!fpiStack.empty() &&
spOffset - kNumActRecCells == fpiStack.top().second) {
for (unsigned i = 0; i < kNumActRecCells; ++i) elem("ActRec");
fpiStack.pop();
if (fpi && spOffset + frameCells == fpi->m_fpOff) {
auto fpushOff = fpi->m_fpushOff;
auto after = fpushOff + instrLen((Op*)curUnit()->at(fpushOff));
std::ostringstream msg;
msg << "ActRec from ";
curUnit()->prettyPrint(msg, Unit::PrintOpts().range(fpushOff, after)
.noLineNumbers()
.indent(0));
auto msgStr = msg.str();
assert(msgStr.back() == '\n');
msgStr.erase(msgStr.size() - 1);
for (unsigned i = 0; i < kNumActRecCells; ++i) elem(msgStr);
fpi = fpi->m_parentIndex != -1 ? &curFunc()->fpitab()[fpi->m_parentIndex]
: nullptr;
return true;
}
return false;
+4 -3
Ver Arquivo
@@ -1337,8 +1337,10 @@ IRTranslator::translateFCall(const NormalizedInstruction& i) {
m_hhbcTrans.profileInlineFunctionShape(traceletShape(*i.calleeTrace));
}
Unit::MetaHandle metaHand;
for (auto* ni = i.calleeTrace->m_instrStream.first;
ni; ni = ni->next) {
readMetaData(metaHand, *ni, m_hhbcTrans, MetaMode::Legacy);
translateInstr(*ni);
}
return;
@@ -1682,15 +1684,14 @@ void IRTranslator::interpretInstr(const NormalizedInstruction& i) {
}
void IRTranslator::translateInstr(const NormalizedInstruction& i) {
m_hhbcTrans.setBcOff(i.source.offset(),
i.breaksTracelet && !m_hhbcTrans.isInlining());
FTRACE(1, "\n{:-^60}\n", folly::format("translating {} with stack:\n{}",
i.toString(),
m_hhbcTrans.showStack()));
// When profiling, we disable type predictions to avoid side exits
assert(Transl::tx64->mode() != TransProfile || !i.outputPredicted);
m_hhbcTrans.setBcOff(i.source.offset(),
i.breaksTracelet && !m_hhbcTrans.isInlining());
if (i.guardedThis) {
// Task #2067635: This should really generate an AssertThis
m_hhbcTrans.setThisAvailable();
+10 -5
Ver Arquivo
@@ -33,6 +33,7 @@ TRACE_SET_MOD(hhir);
//////////////////////////////////////////////////////////////////////
StackValueInfo getStackValue(SSATmp* sp, uint32_t index) {
FTRACE(5, "getStackValue: idx = {}, {}\n", index, sp->inst()->toString());
assert(sp->isA(Type::StkPtr));
IRInstruction* inst = sp->inst();
@@ -84,7 +85,7 @@ StackValueInfo getStackValue(SSATmp* sp, uint32_t index) {
getStackValue(inst->src(0),
// Pushes a return value, pops an ActRec and args Array
index -
(1 /* pushed */ - kNumActRecCells + 1 /* popped */));
(1 /* pushed */ - (kNumActRecCells + 1) /* popped */));
info.spansCall = true;
return info;
}
@@ -97,7 +98,7 @@ StackValueInfo getStackValue(SSATmp* sp, uint32_t index) {
auto info =
getStackValue(inst->src(0),
index -
(1 /* pushed */ - kNumActRecCells /* popped */));
(1 /* pushed */ - kNumActRecCells /* popped */));
info.spansCall = true;
return info;
}
@@ -148,6 +149,10 @@ StackValueInfo getStackValue(SSATmp* sp, uint32_t index) {
if (index == 0) return StackValueInfo { Type::Cell };
if (index == 1) return StackValueInfo { Type::Int };
break;
case Op::FPushCufSafe:
if (index == kNumActRecCells) return StackValueInfo { Type::Bool };
if (index == kNumActRecCells + 1) return getStackValue(prevSp, 0);
break;
default:
if (index == 0 && !resultType.equals(Type::None)) {
@@ -165,9 +170,9 @@ StackValueInfo getStackValue(SSATmp* sp, uint32_t index) {
case SpillFrame:
case CufIterSpillFrame:
return getStackValue(inst->src(0),
// pushes an ActRec
index - kNumActRecCells);
// pushes an ActRec
if (index < kNumActRecCells) return StackValueInfo { nullptr };
return getStackValue(inst->src(0), index - kNumActRecCells);
default:
{
+19 -2
Ver Arquivo
@@ -163,17 +163,34 @@ struct StackValueInfo {
: value(value)
, knownType(value ? value->type() : Type::None)
, spansCall(false)
{}
{
TRACE(5, "%s created\n", show().c_str());
}
explicit StackValueInfo(Type type)
: value(nullptr)
, knownType(type)
, spansCall(false)
{}
{
TRACE(5, "%s created\n", show().c_str());
}
std::string show() const {
std::ostringstream out;
out << "StackValueInfo {";
out << (value ? value->inst()->toString() : knownType.toString());
if (spansCall) out << ", spans call";
out << "}";
return out.str();
}
SSATmp* value; // may be null
Type knownType; // currently Type::None if we don't know (TODO(#2135185)
bool spansCall; // whether the tmp's definition was above a call
private:
TRACE_SET_MOD(hhir);
};
/*
+3
Ver Arquivo
@@ -3468,9 +3468,12 @@ TranslatorX64::translateTracelet(Tracelet& t) {
ht.profileSmallFunctionShape(traceletShape(t));
}();
Unit::MetaHandle metaHand;
// Translate each instruction in the tracelet
for (auto* ni = t.m_instrStream.first; ni && !ht.hasExit();
ni = ni->next) {
readMetaData(metaHand, *ni, m_irTrans->hhbcTrans(), MetaMode::Legacy);
try {
SKTRACE(1, ni->source, "HHIR: translateInstr\n");
assert(!(m_mode == TransProfile && ni->outputPredicted && ni->next));
+50 -16
Ver Arquivo
@@ -1177,7 +1177,7 @@ static const struct {
{ OpFPushCufF, {Stack1, FStack, OutFDesc,
kNumActRecCells - 1 }},
{ OpFPushCufSafe,{StackTop2|DontGuardAny,
StackCufSafe, OutFDesc,
StackTop2|FStack, OutFPushCufSafe,
kNumActRecCells }},
{ OpFPassC, {FuncdRef, None, OutSameAsInput, 0 }},
{ OpFPassCW, {FuncdRef, None, OutSameAsInput, 0 }},
@@ -1266,7 +1266,7 @@ static const struct {
/*** 14. Continuation instructions ***/
{ OpCreateCont, {None, Stack1, OutObject, 1 }},
{ OpCreateCont, {None, Stack1|Local, OutObject, 1 }},
{ OpContEnter, {Stack1, None, OutNone, -1 }},
{ OpUnpackCont, {None, StackTop2, OutInt64, 2 }},
{ OpContSuspend, {Stack1, None, OutNone, -1 }},
@@ -1360,12 +1360,6 @@ int64_t getStackPopped(const NormalizedInstruction& ni) {
}
int64_t getStackPushed(const NormalizedInstruction& ni) {
switch (ni.op()) {
case OpFPushCufSafe: return kNumActRecCells + 2;
default: break;
}
return countOperands(getInstrInfo(ni.op()).out);
}
@@ -1973,6 +1967,7 @@ bool outputDependsOnInput(const Op instr) {
case OutStrlen:
case OutNone:
return false;
case OutFDesc:
case OutSameAsInput:
case OutCInput:
@@ -1986,6 +1981,7 @@ bool outputDependsOnInput(const Op instr) {
case OutSetOp:
case OutIncDec:
case OutSetM:
case OutFPushCufSafe:
return true;
}
not_reached();
@@ -2101,6 +2097,13 @@ void Translator::getOutputs(/*inout*/ Tracelet& t,
varEnvTaint = true;
continue;
}
if (op == OpCreateCont) {
// CreateCont stores Uninit to all locals but NormalizedInstruction
// doesn't have enough output fields, so we special case it in
// analyze().
continue;
}
ASSERT_NOT_IMPLEMENTED(op == OpSetOpL ||
op == OpSetM || op == OpSetOpM ||
op == OpBindM ||
@@ -2283,9 +2286,22 @@ void Translator::getOutputs(/*inout*/ Tracelet& t,
} continue; // already pushed an output for the local
case Stack1:
case Stack2:
case Stack2: {
loc = Location(Location::Stack, currentStackOffset++);
break;
if (ni->op() == OpFPushCufSafe) {
// FPushCufSafe pushes its first stack input, then a bool.
if (opnd == Stack2) {
assert(ni->outStack == nullptr);
auto* dl = t.newDynLocation(loc, ni->inputs[0]->rtt);
ni->outStack = dl;
} else {
assert(ni->outStack2 == nullptr);
auto* dl = t.newDynLocation(loc, KindOfBoolean);
ni->outStack2 = dl;
}
continue;
}
} break;
case StackIns1: {
// First stack output is where the inserted element will go.
// The output code for the instruction will affect what we
@@ -3416,6 +3432,15 @@ std::unique_ptr<Tracelet> Translator::analyze(SrcKey sk,
tas.recordWrite(o);
}
}
if (ni->op() == OpCreateCont) {
// CreateCont stores Uninit to all locals but NormalizedInstruction
// doesn't have enough output fields, so we special case it here.
auto const numLocals = curFunc()->numLocals();
for (unsigned i = 0; i < numLocals; ++i) {
tas.recordWrite(t.newDynLocation(Location(Location::Local, i),
KindOfUninit));
}
}
SKTRACE(1, sk, "stack args: virtual sfo now %d\n", stackFrameOffset);
@@ -3625,7 +3650,7 @@ const char* Translator::translateResultName(TranslateResult r) {
* eventually replace applyInputMetaData.
*/
void readMetaData(Unit::MetaHandle& handle, NormalizedInstruction& inst,
HhbcTranslator& hhbcTrans) {
HhbcTranslator& hhbcTrans, MetaMode metaMode /* = Normal */) {
if (!handle.findMeta(inst.unit(), inst.offset())) return;
Unit::MetaInfo info;
@@ -3660,6 +3685,13 @@ void readMetaData(Unit::MetaHandle& handle, NormalizedInstruction& inst,
!(iInfo.in & Stack2) ? 1 :
!(iInfo.in & Stack3) ? 2 : 3;
auto stackFilter = [metaMode, &inst](Location loc) {
if (metaMode == MetaMode::Legacy && loc.space == Location::Stack) {
loc.offset = -(loc.offset + 1) + inst.stackOffset;
}
return loc;
};
do {
SKTRACE(3, inst.source, "considering MetaInfo of kind %d\n", info.m_kind);
@@ -3667,7 +3699,7 @@ void readMetaData(Unit::MetaHandle& handle, NormalizedInstruction& inst,
base + (info.m_arg & ~Unit::MetaInfo::VectorArg) : info.m_arg;
auto updateType = [&]{
auto& input = *inst.inputs[arg];
input.rtt = hhbcTrans.rttFromLocation(input.location);
input.rtt = hhbcTrans.rttFromLocation(stackFilter(input.location));
};
switch (info.m_kind) {
@@ -3681,7 +3713,8 @@ void readMetaData(Unit::MetaHandle& handle, NormalizedInstruction& inst,
inst.imm[0].u_IVA = info.m_data;
break;
case Unit::MetaInfo::Kind::DataTypePredicted: {
auto const loc = inst.inputs[arg]->location.toLocation();
if (metaMode == MetaMode::Legacy) break;
auto const loc = stackFilter(inst.inputs[arg]->location).toLocation();
auto const t = Type::fromDataType(DataType(info.m_data));
auto const offset = inst.source.offset();
@@ -3695,14 +3728,15 @@ void readMetaData(Unit::MetaHandle& handle, NormalizedInstruction& inst,
}
case Unit::MetaInfo::Kind::DataTypeInferred: {
hhbcTrans.assertTypeLocation(
inst.inputs[arg]->location.toLocation(),
stackFilter(inst.inputs[arg]->location).toLocation(),
Type::fromDataType(DataType(info.m_data)));
updateType();
break;
}
case Unit::MetaInfo::Kind::String: {
hhbcTrans.assertString(inst.inputs[arg]->location.toLocation(),
inst.unit()->lookupLitstrId(info.m_data));
hhbcTrans.assertString(
stackFilter(inst.inputs[arg]->location).toLocation(),
inst.unit()->lookupLitstrId(info.m_data));
updateType();
break;
}
+8 -2
Ver Arquivo
@@ -1073,7 +1073,12 @@ SrcKey nextSrcKey(const NormalizedInstruction& i);
void populateImmediates(NormalizedInstruction&);
void preInputApplyMetaData(Unit::MetaHandle, NormalizedInstruction*);
void readMetaData(Unit::MetaHandle&, NormalizedInstruction&, HhbcTranslator&);
enum class MetaMode {
Normal,
Legacy,
};
void readMetaData(Unit::MetaHandle&, NormalizedInstruction&, HhbcTranslator&,
MetaMode m = MetaMode::Normal);
bool instrMustInterp(const NormalizedInstruction&);
typedef std::function<Type(int)> LocalTypeFn;
@@ -1122,6 +1127,8 @@ enum OutTypeConstraints {
OutStrlen, // OpStrLen
OutClassRef, // KindOfClass
OutSetM, // SetM is a very special snowflake
OutFPushCufSafe, // FPushCufSafe pushes two values of different
// types and an ActRec
OutNone
};
@@ -1156,7 +1163,6 @@ enum Operands {
// n = imm[0].u_IVA
StackTop2 = Stack1 | Stack2,
StackTop3 = Stack1 | Stack2 | Stack3,
StackCufSafe = StackIns1 | FStack
};
inline Operands operator|(const Operands& l, const Operands& r) {