TailCallRemover.cs 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. using System;
  2. using System.Collections.Generic;
  3. namespace ARMeilleure.Decoders.Optimizations
  4. {
  5. static class TailCallRemover
  6. {
  7. public static Block[] RunPass(ulong entryAddress, List<Block> blocks)
  8. {
  9. // Detect tail calls:
  10. // - Assume this function spans the space covered by contiguous code blocks surrounding the entry address.
  11. // - A jump to an area outside this contiguous region will be treated as an exit block.
  12. // - Include a small allowance for jumps outside the contiguous range.
  13. if (!Decoder.BinarySearch(blocks, entryAddress, out int entryBlockId))
  14. {
  15. throw new InvalidOperationException("Function entry point is not contained in a block.");
  16. }
  17. const ulong allowance = 4;
  18. Block entryBlock = blocks[entryBlockId];
  19. Block startBlock = entryBlock;
  20. Block endBlock = entryBlock;
  21. int startBlockIndex = entryBlockId;
  22. int endBlockIndex = entryBlockId;
  23. for (int i = entryBlockId + 1; i < blocks.Count; i++) // Search forwards.
  24. {
  25. Block block = blocks[i];
  26. if (endBlock.EndAddress < block.Address - allowance)
  27. {
  28. break; // End of contiguous function.
  29. }
  30. endBlock = block;
  31. endBlockIndex = i;
  32. }
  33. for (int i = entryBlockId - 1; i >= 0; i--) // Search backwards.
  34. {
  35. Block block = blocks[i];
  36. if (startBlock.Address > block.EndAddress + allowance)
  37. {
  38. break; // End of contiguous function.
  39. }
  40. startBlock = block;
  41. startBlockIndex = i;
  42. }
  43. if (startBlockIndex == 0 && endBlockIndex == blocks.Count - 1)
  44. {
  45. return blocks.ToArray(); // Nothing to do here.
  46. }
  47. // Mark branches whose target is outside of the contiguous region as an exit block.
  48. for (int i = startBlockIndex; i <= endBlockIndex; i++)
  49. {
  50. Block block = blocks[i];
  51. if (block.Branch != null && (block.Branch.Address > endBlock.EndAddress || block.Branch.EndAddress < startBlock.Address))
  52. {
  53. block.Branch.Exit = true;
  54. }
  55. }
  56. var newBlocks = new List<Block>(blocks.Count);
  57. // Finally, rebuild decoded block list, ignoring blocks outside the contiguous range.
  58. for (int i = 0; i < blocks.Count; i++)
  59. {
  60. Block block = blocks[i];
  61. if (block.Exit || (i >= startBlockIndex && i <= endBlockIndex))
  62. {
  63. newBlocks.Add(block);
  64. }
  65. }
  66. return newBlocks.ToArray();
  67. }
  68. }
  69. }