| 236 | |
| 237 | |
| 238 | void Inliner::optimise() |
| 239 | { |
| 240 | std::map<size_t, InlinableBlock> inlinableBlocks = determineInlinableBlocks(m_items); |
| 241 | |
| 242 | if (inlinableBlocks.empty()) |
| 243 | return; |
| 244 | |
| 245 | AssemblyItems newItems; |
| 246 | for (auto it = m_items.begin(); it != m_items.end(); ++it) |
| 247 | { |
| 248 | AssemblyItem const& item = *it; |
| 249 | if (next(it) != m_items.end()) |
| 250 | { |
| 251 | AssemblyItem const& nextItem = *next(it); |
| 252 | if (item.type() == PushTag && nextItem == Instruction::JUMP) |
| 253 | { |
| 254 | if (std::optional<size_t> tag = getLocalTag(item)) |
| 255 | if (auto* inlinableBlock = util::valueOrNullptr(inlinableBlocks, *tag)) |
| 256 | if (auto exitItem = shouldInline(*tag, nextItem, *inlinableBlock)) |
| 257 | { |
| 258 | newItems += inlinableBlock->items | ranges::views::drop_last(1); |
| 259 | newItems.emplace_back(std::move(*exitItem)); |
| 260 | |
| 261 | // We are removing one push tag to the block we inline. |
| 262 | --inlinableBlock->pushTagCount; |
| 263 | // We might increase the number of push tags to other blocks. |
| 264 | for (AssemblyItem const& inlinedItem: inlinableBlock->items) |
| 265 | if (inlinedItem.type() == PushTag) |
| 266 | if (std::optional<size_t> duplicatedTag = getLocalTag(inlinedItem)) |
| 267 | if (auto* block = util::valueOrNullptr(inlinableBlocks, *duplicatedTag)) |
| 268 | ++block->pushTagCount; |
| 269 | |
| 270 | // Skip the original jump to the inlined tag and continue. |
| 271 | ++it; |
| 272 | continue; |
| 273 | } |
| 274 | } |
| 275 | } |
| 276 | newItems.emplace_back(item); |
| 277 | } |
| 278 | |
| 279 | m_items = std::move(newItems); |
| 280 | } |
no test coverage detected