/* * Compute the stack and local type postconditions for a * single-entry/single-exit tracelet. */ std::vector<RegionDesc::TypePred> IRBuilder::getKnownTypes() { // This function is only correct when given a single-exit region, as // in TransProfile. Furthermore, its output is only used to guide // formation of profile-driven regions. assert(tx->mode() == TransProfile); // We want the state for the last block on the "main trace". Figure // out which that is. Block* mainExit = nullptr; for (auto* b : rpoSortCfg(m_unit)) { if (isMainExit(b)) { assert(mainExit == nullptr); mainExit = b; } } assert(mainExit != nullptr); // Load state for mainExit. This feels hacky. FTRACE(1, "mainExit: B{}\n", mainExit->id()); m_state.startBlock(mainExit); // Now use the current state to get all the types. std::vector<RegionDesc::TypePred> result; auto const curFunc = m_state.func(); auto const sp = m_state.sp(); auto const spOffset = m_state.spOffset(); for (unsigned i = 0; i < curFunc->maxStackCells(); ++i) { auto t = getStackValue(sp, i).knownType; if (!t.equals(Type::StackElem)) { result.push_back({ RegionDesc::Location::Stack{i, spOffset - i}, t }); } } for (unsigned i = 0; i < curFunc->numLocals(); ++i) { auto t = m_state.localType(i); if (!t.equals(Type::Gen)) { FTRACE(1, "Local {}: {}\n", i, t.toString()); result.push_back({ RegionDesc::Location::Local{i}, t }); } } return result; }
/* * Intended to be called after all optimizations are finished on a * single-entry, single-exit tracelet, this collects the types of all stack * slots and locals at the end of the main exit. */ void IRUnit::collectPostConditions() { // This function is only correct when given a single-exit region, as in // TransKind::Profile. Furthermore, its output is only used to guide // formation of profile-driven regions. assert(mcg->tx().mode() == TransKind::Profile); assert(m_postConds.empty()); Timer _t(Timer::collectPostConditions); // We want the state for the last block on the "main trace". Figure // out which that is. Block* mainExit = nullptr; Block* lastMainBlock = nullptr; FrameStateMgr state{*this, entry()->front().marker()}; // TODO(#5678127): this code is wrong for HHIRBytecodeControlFlow state.setLegacyReoptimize(); ITRACE(2, "collectPostConditions starting\n"); Trace::Indent _i; for (auto* block : rpoSortCfg(*this)) { state.startBlock(block, block->front().marker()); for (auto& inst : *block) { state.update(&inst); } if (isMainBlock(block)) lastMainBlock = block; if (isMainExit(block)) { mainExit = block; break; } state.finishBlock(block); } // If we didn't find an obvious exit, then use the last block in the region. always_assert(lastMainBlock != nullptr); if (mainExit == nullptr) mainExit = lastMainBlock; FTRACE(1, "mainExit: B{}\n", mainExit->id()); // state currently holds the state at the end of mainExit auto const curFunc = state.func(); auto const sp = state.sp(); auto const spOffset = state.spOffset(); for (unsigned i = 0; i < spOffset; ++i) { auto t = getStackValue(sp, i).knownType; if (!t.equals(Type::StackElem)) { m_postConds.push_back({ RegionDesc::Location::Stack{i, spOffset - i}, t }); } } for (unsigned i = 0; i < curFunc->numLocals(); ++i) { auto t = state.localType(i); if (!t.equals(Type::Gen)) { FTRACE(1, "Local {}: {}\n", i, t.toString()); m_postConds.push_back({ RegionDesc::Location::Local{i}, t }); } } }