diff options
Diffstat (limited to 'ARMeilleure/Decoders/Optimizations')
| -rw-r--r-- | ARMeilleure/Decoders/Optimizations/TailCallRemover.cs | 50 |
1 files changed, 32 insertions, 18 deletions
diff --git a/ARMeilleure/Decoders/Optimizations/TailCallRemover.cs b/ARMeilleure/Decoders/Optimizations/TailCallRemover.cs index 2d6439ba..e64f9a54 100644 --- a/ARMeilleure/Decoders/Optimizations/TailCallRemover.cs +++ b/ARMeilleure/Decoders/Optimizations/TailCallRemover.cs @@ -1,16 +1,15 @@ -using ARMeilleure.Decoders; -using System; +using System; using System.Collections.Generic; namespace ARMeilleure.Decoders.Optimizations { static class TailCallRemover { - public static void RunPass(ulong entryAddress, List<Block> blocks) + public static Block[] RunPass(ulong entryAddress, List<Block> blocks) { // Detect tail calls: // - Assume this function spans the space covered by contiguous code blocks surrounding the entry address. - // - Unconditional jump to an area outside this contiguous region will be treated as a tail call. + // - A jump to an area outside this contiguous region will be treated as an exit block. // - Include a small allowance for jumps outside the contiguous range. if (!Decoder.BinarySearch(blocks, entryAddress, out int entryBlockId)) @@ -19,57 +18,72 @@ namespace ARMeilleure.Decoders.Optimizations } const ulong allowance = 4; + Block entryBlock = blocks[entryBlockId]; - int startBlockIndex = entryBlockId; + Block startBlock = entryBlock; - int endBlockIndex = entryBlockId; - Block endBlock = entryBlock; + Block endBlock = entryBlock; + + int startBlockIndex = entryBlockId; + int endBlockIndex = entryBlockId; for (int i = entryBlockId + 1; i < blocks.Count; i++) // Search forwards. { Block block = blocks[i]; + if (endBlock.EndAddress < block.Address - allowance) { break; // End of contiguous function. } - endBlock = block; + endBlock = block; endBlockIndex = i; } for (int i = entryBlockId - 1; i >= 0; i--) // Search backwards. { Block block = blocks[i]; + if (startBlock.Address > block.EndAddress + allowance) { break; // End of contiguous function. } - startBlock = block; + startBlock = block; startBlockIndex = i; } if (startBlockIndex == 0 && endBlockIndex == blocks.Count - 1) { - return; // Nothing to do here. + return blocks.ToArray(); // Nothing to do here. } - - // Replace all branches to blocks outside the range with null, and force a tail call. - + + // Mark branches outside of contiguous region as exit blocks. for (int i = startBlockIndex; i <= endBlockIndex; i++) { Block block = blocks[i]; + if (block.Branch != null && (block.Branch.Address > endBlock.EndAddress || block.Branch.EndAddress < startBlock.Address)) { - block.Branch = null; - block.TailCall = true; + block.Branch.Exit = true; + block.Branch.TailCall = true; } } - // Finally, delete all blocks outside the contiguous range. + var newBlocks = new List<Block>(blocks.Count); + + // Finally, rebuild decoded block list, ignoring blocks outside the contiguous range. + for (int i = 0; i < blocks.Count; i++) + { + Block block = blocks[i]; + + if (block.Exit || (i >= startBlockIndex && i <= endBlockIndex)) + { + newBlocks.Add(block); + } + } - blocks.RemoveRange(endBlockIndex + 1, (blocks.Count - endBlockIndex) - 1); - blocks.RemoveRange(0, startBlockIndex); + return newBlocks.ToArray(); } } } |
