SSATmp* Simplifier::simplifyGuardType(IRInstruction* inst) { Type type = inst->getTypeParam(); SSATmp* src = inst->getSrc(0); Type srcType = src->getType(); if (srcType == type || srcType.strictSubtypeOf(type)) { /* * the type of the src is the same or more refined than type, so the * guard is unnecessary. */ return src; } if (type.strictSubtypeOf(srcType)) { if (hoistGuardToLoad(src, type)) { return src; } } else { /* * incompatible types! We should just generate a jump here and * return null. * * For now, this case should currently be impossible, but it may * come up later due to other optimizations. The assert is so * we'll remember this spot ... */ assert(0); } return nullptr; }
/* * Looks for whether the value in tmp was defined by a load, and if * so, changes that load into a load that guards on the given * type. Returns true if it succeeds. */ static bool hoistGuardToLoad(SSATmp* tmp, Type type) { IRInstruction* inst = tmp->getInstruction(); switch (inst->getOpcode()) { case Mov: case IncRef: { // if inst is an incref or move, then chase down its src if (hoistGuardToLoad(inst->getSrc(0), type)) { // guard was successfully attached to a load instruction // refine the type of this mov/incref // Note: We can also further simplify incref's here if type is not // ref-counted tmp->setType(type); inst->setTypeParam(type); return true; } break; } case LdLoc: case LdStack: case LdMem: case LdProp: case LdRef: case LdClsCns: { if (!inst->getTaken()) { // Not a control flow instruction, so can't give it check semantics break; } Type instType = tmp->getType(); if (instType == Type::Gen || (instType == Type::Cell && !type.isBoxed())) { tmp->setType(type); inst->setTypeParam(type); return true; } break; } default: break; } return false; }
SSATmp* Simplifier::simplifyGuardType(IRInstruction* inst) { Type type = inst->getTypeParam(); SSATmp* src = inst->getSrc(0); Type srcType = src->getType(); if (srcType.subtypeOf(type)) { /* * the type of the src is the same or more refined than type, so the * guard is unnecessary. */ return src; } if (type.strictSubtypeOf(srcType)) { if (hoistGuardToLoad(src, type)) { return src; } } else { if (type.equals(Type::Str) && srcType.maybe(Type::Str)) { // If we're guarding against Str and srcType has StaticStr or CountedStr // in it, refine the output type. This can happen when we have a // KindOfString guard from Translator but internally we know a more // specific subtype of Str. FTRACE(1, "Guarding {} to {}\n", srcType.toString(), type.toString()); inst->setTypeParam(type & srcType); } else { /* * incompatible types! We should just generate a jump here and * return null. * * For now, this case should currently be impossible, but it may * come up later due to other optimizations. The assert is so * we'll remember this spot ... */ not_implemented(); } } return nullptr; }