relax guard change to allow for specialized guards

Unified code for relax and specialize guards and removed type propagation on relaxation
Esse commit está contido em:
Dario Russi
2013-07-03 14:34:08 -07:00
commit de Sara Golemon
commit 54b8a31c6f
4 arquivos alterados com 104 adições e 143 exclusões
+2 -1
Ver Arquivo
@@ -81,7 +81,8 @@ enum DataTypeCategory {
DataTypeGeneric,
DataTypeCountness,
DataTypeCountnessInit,
DataTypeSpecific
DataTypeSpecific,
DataTypeSpecialized
};
///////////////////////////////////////////////////////////////////////////////
+10 -7
Ver Arquivo
@@ -371,15 +371,18 @@ string RuntimeType::pretty() const {
sprintf(buf, "(Value %s)", tname(m_value.outerType).c_str());
}
string retval = buf;
if (valueType() == KindOfObject && valueClass() != nullptr) {
char buf2[1024];
sprintf(buf2, "(OfClass %s)", valueClass()->preClass()->name()->data());
retval += string(buf2);
if (valueType() == KindOfObject) {
if (valueClass() != nullptr) {
retval += folly::format("(OfClass {})",
knownClass()->name()->data()).str();
} else if (hasKnownType()) {
retval += folly::format("(Known Class {})",
knownClass()->name()->data()).str();
}
}
if (valueType() == KindOfClass && valueClass() != nullptr) {
char buf2[1024];
sprintf(buf2, "(Class %s)", valueClass()->preClass()->name()->data());
retval += string(buf2);
retval += folly::format("(Class {})",
knownClass()->name()->data()).str();
}
return retval;
}
+84 -126
Ver Arquivo
@@ -2327,7 +2327,7 @@ DynLocation* TraceletContext::recordRead(const InputInfo& ii,
m_resolvedDeps[l] = dl;
}
} else {
RuntimeType rtt = tx64->liveType(l, *curUnit());
RuntimeType rtt = tx64->liveType(l, *curUnit(), true);
assert(rtt.isIter() || !rtt.isVagueValue());
// Allocate a new DynLocation to represent this and store it in the
// current map.
@@ -2502,13 +2502,14 @@ bool NormalizedInstruction::isAnyOutputUsed() const
}
GuardType::GuardType(DataType outer, DataType inner)
: outerType(outer), innerType(inner) {
: outerType(outer), innerType(inner), klass(nullptr) {
}
GuardType::GuardType(const RuntimeType& rtt) {
assert(rtt.isValue());
outerType = rtt.outerType();
innerType = rtt.innerType();
klass = rtt.hasKnownType() ? rtt.knownClass() : nullptr;
}
GuardType::GuardType(const GuardType& other) {
@@ -2524,10 +2525,18 @@ const DataType GuardType::getInnerType() const {
return innerType;
}
const Class* GuardType::getSpecializedClass() const {
return klass;
}
bool GuardType::isSpecific() const {
return outerType > KindOfInvalid;
}
bool GuardType::isSpecialized() const {
return outerType == KindOfObject && klass != nullptr;
}
bool GuardType::isRelaxed() const {
switch (outerType) {
case KindOfAny:
@@ -2566,7 +2575,9 @@ DataTypeCategory GuardType::getCategory() const {
case KindOfAny: return DataTypeGeneric;
case KindOfUncounted: return DataTypeCountness;
case KindOfUncountedInit: return DataTypeCountnessInit;
default: return DataTypeSpecific;
default: return klass != nullptr ?
DataTypeSpecialized :
DataTypeSpecific;
}
}
@@ -2592,10 +2603,27 @@ GuardType GuardType::getCountness() const {
case KindOfBoolean:
case KindOfInt64:
case KindOfDouble: return GuardType(KindOfUncounted);
default: return *this;
default: return GuardType(outerType, innerType);
}
}
GuardType GuardType::dropSpecialization() const {
return GuardType(outerType, innerType);
}
RuntimeType GuardType::getRuntimeType() const {
if (klass != nullptr) {
return RuntimeType(outerType, innerType).setKnownClass(klass);
}
return RuntimeType(outerType, innerType);
}
bool GuardType::isEqual(GuardType other) const {
return outerType == other.outerType &&
innerType == other.innerType &&
klass == other.klass;
}
GuardType GuardType::getCountnessInit() const {
assert(isSpecific());
switch (outerType) {
@@ -2603,7 +2631,7 @@ GuardType GuardType::getCountnessInit() const {
case KindOfBoolean:
case KindOfInt64:
case KindOfDouble: return GuardType(KindOfUncountedInit);
default: return *this;
default: return GuardType(outerType, innerType);
}
}
@@ -2625,7 +2653,8 @@ bool isPopped(DynLocation* loc, NormalizedInstruction* instr) {
DataTypeCategory
Translator::getOperandConstraintCategory(NormalizedInstruction* instr,
size_t opndIdx) {
size_t opndIdx,
const GuardType& specType) {
auto opc = instr->op();
switch (opc) {
@@ -2691,6 +2720,28 @@ Translator::getOperandConstraintCategory(NormalizedInstruction* instr,
// which takes care of dec-refing it if needed
return opndIdx == 0 ? DataTypeGeneric : DataTypeSpecific;
//
// Collections and Iterator related specializations
//
case OpCGetM:
case OpIssetM:
case OpFPassM:
if (instr->inputs.size() == 2 && opndIdx == 0) {
const Class* klass = specType.getSpecializedClass();
if (klass != nullptr && isOptimizableCollectionClass(klass)) {
return DataTypeSpecialized;
}
}
return DataTypeSpecific;
case OpSetM:
if (instr->inputs.size() == 3 && opndIdx == 1) {
const Class* klass = specType.getSpecializedClass();
if (klass != nullptr && isOptimizableCollectionClass(klass)) {
return DataTypeSpecialized;
}
}
return DataTypeSpecific;
default:
return DataTypeSpecific;
}
@@ -2700,21 +2751,25 @@ GuardType
Translator::getOperandConstraintType(NormalizedInstruction* instr,
size_t opndIdx,
const GuardType& specType) {
DataTypeCategory dtCategory = getOperandConstraintCategory(instr, opndIdx);
DataTypeCategory dtCategory = getOperandConstraintCategory(instr,
opndIdx,
specType);
switch (dtCategory) {
case DataTypeGeneric: return GuardType(KindOfAny);
case DataTypeCountness: return specType.getCountness();
case DataTypeCountnessInit: return specType.getCountnessInit();
case DataTypeSpecific:
default: return specType;
case DataTypeSpecific: return specType.dropSpecialization();
case DataTypeSpecialized:
return specType;
}
return specType;
}
void Translator::constrainOperandType(GuardType& relxType,
NormalizedInstruction* instr,
size_t opndIdx,
const GuardType& specType) {
if (relxType.isSpecific()) return; // Can't constrain any further
if (relxType.isEqual(specType)) return; // Can't constrain any further
GuardType consType = getOperandConstraintType(instr, opndIdx, specType);
if (consType.isMoreRefinedThan(relxType)) {
@@ -2733,7 +2788,7 @@ void Translator::constrainDep(const DynLocation* loc,
NormalizedInstruction* firstInstr,
GuardType specType,
GuardType& relxType) {
if (relxType.isSpecific()) return; // can't contrain it any further
if (relxType.isEqual(specType)) return; // can't contrain it any further
for (NormalizedInstruction* instr = firstInstr; instr; instr = instr->next) {
if (instr->noOp) continue;
@@ -2765,13 +2820,17 @@ void Translator::constrainDep(const DynLocation* loc,
if (specType.getOuterType() == KindOfRef &&
instr->isAnyOutputUsed()) {
// Value gets unboxed along the way. Pessimize it for now.
relxType = specType;
if (!relxType.isSpecialized()) {
relxType = specType.dropSpecialization();
}
return;
}
break;
default:
relxType = specType;
if (!relxType.isSpecialized()) {
relxType = specType.dropSpecialization();
}
return;
}
@@ -2797,67 +2856,6 @@ void Translator::constrainDep(const DynLocation* loc,
}
}
/**
* Propagates the relaxed type relxType for loc to all its consumers,
* starting at firstInstr.
*/
void Translator::propagateRelaxedType(Tracelet& tclet,
NormalizedInstruction* firstInstr,
DynLocation* loc,
const GuardType& relxType) {
assert(relxType.isRelaxed());
for (NormalizedInstruction* instr = firstInstr; instr; instr = instr->next) {
if (instr->noOp) continue;
auto opc = instr->op();
size_t nInputs = instr->inputs.size();
for (size_t i = 0; i < nInputs; i++) {
DynLocation* usedLoc = instr->inputs[i];
if (usedLoc == loc) {
auto outKind = instrInfo[opc].type;
// stack input propagates to outputs
bool outputIsStackInput = (i == 0 && // stack input is inputs[0]
(outKind == OutSameAsInput || outKind == OutCInput));
bool outputIsLocalInput = (i == nInputs - 1 && // local input is last
outKind == OutCInputL);
bool outputIsInput = outputIsStackInput || outputIsLocalInput;
if (outputIsInput) {
// if instr has outStack, update its type and propagate to consumers
if (instr->outStack) {
TRACE(6,
"propagateRelaxedType: Loc: %s oldType: %s => newType: %s\n",
instr->outStack->location.pretty().c_str(),
instr->outStack->rtt.pretty().c_str(),
RuntimeType(relxType.getOuterType(),
relxType.getInnerType()).pretty().c_str());
instr->outStack->rtt = RuntimeType(relxType.getOuterType(),
relxType.getInnerType());
propagateRelaxedType(tclet, instr->next, instr->outStack, relxType);
}
// if instr has outLocal, update its type and propagate to consumers
if (instr->outLocal) {
TRACE(6,
"propagateRelaxedType: Loc: %s oldType: %s => newType: %s\n",
instr->outLocal->location.pretty().c_str(),
instr->outLocal->rtt.pretty().c_str(),
RuntimeType(relxType.getOuterType(),
relxType.getInnerType()).pretty().c_str());
instr->outLocal->rtt = RuntimeType(relxType.getOuterType(),
relxType.getInnerType());
propagateRelaxedType(tclet, instr->next, instr->outLocal, relxType);
}
}
}
}
}
}
/*
* This method looks at all the uses of the tracelet dependencies in the
* instruction stream and tries to relax the type associated with each location.
@@ -2876,7 +2874,9 @@ void Translator::relaxDeps(Tracelet& tclet, TraceletContext& tctxt) {
GuardType relxType = GuardType(KindOfAny);
GuardType specType = GuardType(rtt);
constrainDep(loc, tclet.m_instrStream.first, specType, relxType);
locRelxTypeMap[loc] = relxType;
if (!specType.isEqual(relxType)) {
locRelxTypeMap[loc] = relxType;
}
}
}
@@ -2885,56 +2885,15 @@ void Translator::relaxDeps(Tracelet& tclet, TraceletContext& tctxt) {
for (auto& kv : locRelxTypeMap) {
DynLocation* loc = kv.first;
const GuardType& relxType = kv.second;
if (relxType.isRelaxed()) {
TRACE(1, "relaxDeps: Loc: %s oldType: %s => newType: %s\n",
loc->location.pretty().c_str(),
deps[loc->location]->rtt.pretty().c_str(),
RuntimeType(relxType.getOuterType(),
relxType.getInnerType()).pretty().c_str());
assert(deps[loc->location] == loc);
assert(relxType.getOuterType() != KindOfInvalid);
deps[loc->location]->rtt = RuntimeType(relxType.getOuterType(),
relxType.getInnerType());
propagateRelaxedType(tclet, tclet.m_instrStream.first, loc, relxType);
}
}
}
/*
* This method looks at all the uses of the tracelet dependencies in the
* instruction stream and tries to specialize the type associated
* with each location.
*/
void Translator::specializeDeps(Tracelet& tclet, TraceletContext& tctxt) {
// Process the instruction stream, look for CGetM/SetM/IssetM and if the
// instructions are for Vector types and consistent with Vector usage
// specialize the guard
for (NormalizedInstruction* instr = tclet.m_instrStream.first; instr;
instr = instr->next) {
auto op = instr->op();
if ((op == OpCGetM || op == OpIssetM || op == OpFPassM) &&
instr->inputs.size() == 2) {
specializeCollections(instr, 0, tctxt);
} else if (op == OpSetM && instr->inputs.size() == 3) {
specializeCollections(instr, 1, tctxt);
}
}
}
void Translator::specializeCollections(NormalizedInstruction* instr,
int index,
TraceletContext& tctxt) {
if (instr->inputs[index]->isObject()
|| instr->inputs[index]->isRefToObject()) {
Location l = instr->inputs[index]->location;
auto dep = tctxt.m_dependencies.find(l);
if (dep != tctxt.m_dependencies.end()) {
RuntimeType specialized = liveType(l, *curUnit(), true);
const Class* klass = specialized.knownClass();
if (klass != nullptr && isOptimizableCollectionClass(klass)) {
tctxt.m_dependencies[l]->rtt = specialized;
}
}
TRACE(1, "relaxDeps: Loc: %s oldType: %s => newType: %s\n",
loc->location.pretty().c_str(),
deps[loc->location]->rtt.pretty().c_str(),
RuntimeType(relxType.getOuterType(),
relxType.getInnerType(),
relxType.getSpecializedClass()).pretty().c_str());
assert(deps[loc->location] == loc);
assert(relxType.getOuterType() != KindOfInvalid);
deps[loc->location]->rtt = relxType.getRuntimeType();
}
}
@@ -3510,7 +3469,6 @@ breakBB:
}
relaxDeps(t, tas);
specializeDeps(t, tas);
// Mark the last instruction appropriately
assert(t.m_instrStream.last);
+8 -9
Ver Arquivo
@@ -371,7 +371,9 @@ class GuardType {
GuardType(const GuardType& other);
const DataType getOuterType() const;
const DataType getInnerType() const;
const Class* getSpecializedClass() const;
bool isSpecific() const;
bool isSpecialized() const;
bool isRelaxed() const;
bool isGeneric() const;
bool isCounted() const;
@@ -380,10 +382,14 @@ class GuardType {
GuardType getCountness() const;
GuardType getCountnessInit() const;
DataTypeCategory getCategory() const;
GuardType dropSpecialization() const;
RuntimeType getRuntimeType() const;
bool isEqual(GuardType other) const;
private:
DataType outerType;
DataType innerType;
const Class* klass;
};
/*
@@ -705,20 +711,13 @@ private:
int& currentStackOffset,
bool& varEnvTaint);
void relaxDeps(Tracelet& tclet, TraceletContext& tctxt);
void propagateRelaxedType(Tracelet& tclet,
NormalizedInstruction* firstInstr,
DynLocation* loc,
const GuardType& relxType);
void constrainDep(const DynLocation* loc,
NormalizedInstruction* firstInstr,
GuardType specType,
GuardType& relxType);
void specializeDeps(Tracelet& tclet, TraceletContext& tctxt);
void specializeCollections(NormalizedInstruction* instr,
int index,
TraceletContext& tctxt);
DataTypeCategory getOperandConstraintCategory(NormalizedInstruction* instr,
size_t opndIdx);
size_t opndIdx,
const GuardType& specType);
GuardType getOperandConstraintType(NormalizedInstruction* instr,
size_t opndIdx,
const GuardType& specType);