TailCallRemover.cs 2.7 KB

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