// XXX: to be refactored // This function repeats the logic in cg to pre-color tmps that are // going to be used in next native. void LinearScan::computePreColoringHint() { m_preColoringHint.clear(); IRInstruction* nextNative = getNextNative(); if (nextNative == NULL) { return; } auto normalHint = [&](int count, int srcBase = 0, int argBase = 0) { for (int i = 0; i < count; ++i) { m_preColoringHint.add(nextNative->getSrc(i + srcBase), 0, i + argBase); } }; switch (nextNative->getOpcode()) { case Box: if (nextNative->getSrc(0)->getType() == Type::Cell) { m_preColoringHint.add(nextNative->getSrc(0), 1, 0); } m_preColoringHint.add(nextNative->getSrc(0), 0, 1); break; case LdObjMethod: m_preColoringHint.add(nextNative->getSrc(1), 0, 1); m_preColoringHint.add(nextNative->getSrc(0), 0, 2); break; case LdFunc: m_preColoringHint.add(nextNative->getSrc(0), 0, 1); break; case NativeImpl: m_preColoringHint.add(nextNative->getSrc(1), 0, 0); break; case Print: m_preColoringHint.add(nextNative->getSrc(0), 0, 0); break; case AddElem: if (nextNative->getSrc(1)->getType() == Type::Int && nextNative->getSrc(2)->getType() == Type::Int) { normalHint(3, 0, 1); } else { m_preColoringHint.add(nextNative->getSrc(0), 0, 0); m_preColoringHint.add(nextNative->getSrc(1), 0, 1); m_preColoringHint.add(nextNative->getSrc(2), 0, 2); m_preColoringHint.add(nextNative->getSrc(2), 1, 3); } break; case AddNewElem: m_preColoringHint.add(nextNative->getSrc(0), 0, 0); m_preColoringHint.add(nextNative->getSrc(1), 0, 1); m_preColoringHint.add(nextNative->getSrc(1), 1, 2); break; case Concat: { Type::Tag lType = nextNative->getSrc(0)->getType(); Type::Tag rType = nextNative->getSrc(1)->getType(); if ((Type::isString(lType) && Type::isString(rType)) || (Type::isString(lType) && rType == Type::Int) || (lType == Type::Int && Type::isString(rType))) { m_preColoringHint.add(nextNative->getSrc(0), 0, 0); m_preColoringHint.add(nextNative->getSrc(1), 0, 1); } else { m_preColoringHint.add(nextNative->getSrc(0), 0, 1); m_preColoringHint.add(nextNative->getSrc(1), 0, 3); } } break; case ArrayAdd: normalHint(2); break; case DefFunc: normalHint(1); break; case CreateCont: normalHint(4); break; case FillContLocals: normalHint(4); break; case OpEq: case OpNeq: case OpSame: case OpNSame: { auto src1 = nextNative->getSrc(0); auto src2 = nextNative->getSrc(1); auto type1 = src1->getType(); auto type2 = src2->getType(); if ((type1 == Type::Arr && type2 == Type::Arr) || (Type::isString(type1) && Type::isString(type2)) || (Type::isString(type1) && !src1->isConst()) || (type1 == Type::Obj && type2 == Type::Obj)) { m_preColoringHint.add(src1, 0, 0); m_preColoringHint.add(src2, 0, 1); } } break; case IterInit: { m_preColoringHint.add(nextNative->getSrc(0), 0, 1); } break; case Conv: { SSATmp* src = nextNative->getSrc(0); Type::Tag toType = nextNative->getTypeParam(); Type::Tag fromType = src->getType(); if (toType == Type::Bool) { switch (fromType) { case Type::Cell: m_preColoringHint.add(src, 0, 0); m_preColoringHint.add(src, 1, 1); break; case Type::Str: case Type::StaticStr: case Type::Arr: case Type::Obj: m_preColoringHint.add(src, 0, 0); break; default: break; } } else if (Type::isString(toType)) { if (fromType == Type::Int) { m_preColoringHint.add(src, 0, 0); } } else if (Type::isString(fromType) && toType == Type::Int) { m_preColoringHint.add(src, 0, 0); } break; } default: break; } }
void eliminateDeadCode(Trace* trace, IRFactory* irFactory) { auto removeEmptyExitTraces = [&] { trace->getExitTraces().remove_if([](Trace* exit) { return exit->getBlocks().empty(); }); }; // kill unreachable code and remove any traces that are now empty BlockList blocks = removeUnreachable(trace, irFactory); removeEmptyExitTraces(); // mark the essential instructions and add them to the initial // work list; this will also mark reachable exit traces. All // other instructions marked dead. DceState state(irFactory, DceFlags()); WorkList wl = initInstructions(trace, blocks, state, irFactory); // process the worklist while (!wl.empty()) { auto* inst = wl.front(); wl.pop_front(); for (uint32_t i = 0; i < inst->getNumSrcs(); i++) { SSATmp* src = inst->getSrc(i); if (src->getInstruction()->getOpcode() == DefConst) { continue; } IRInstruction* srcInst = src->getInstruction(); if (state[srcInst].isDead()) { state[srcInst].setLive(); wl.push_back(srcInst); } // <inst> consumes <srcInst> which is an IncRef, so we mark <srcInst> as // REFCOUNT_CONSUMED. If the source instruction is a GuardType and guards // to a maybeCounted type, we need to trace through to the source for // refcounting purposes. while (srcInst->getOpcode() == GuardType && srcInst->getTypeParam().maybeCounted()) { srcInst = srcInst->getSrc(0)->getInstruction(); } if (inst->consumesReference(i) && srcInst->getOpcode() == IncRef) { if (inst->getTrace()->isMain() || !srcInst->getTrace()->isMain()) { // <srcInst> is consumed from its own trace. state[srcInst].setCountConsumed(); } else { // <srcInst> is consumed off trace. if (!state[srcInst].countConsumed()) { // mark <srcInst> as REFCOUNT_CONSUMED_OFF_TRACE unless it is // also consumed from its own trace. state[srcInst].setCountConsumedOffTrace(); } } } } } // Optimize IncRefs and DecRefs. forEachTrace(trace, [&](Trace* t) { optimizeRefCount(t, state); }); if (RuntimeOption::EvalHHIREnableSinking) { // Sink IncRefs consumed off trace. sinkIncRefs(trace, irFactory, state); } // now remove instructions whose id == DEAD removeDeadInstructions(trace, state); for (Trace* exit : trace->getExitTraces()) { removeDeadInstructions(exit, state); } // and remove empty exit traces removeEmptyExitTraces(); }