TailMerge.cs 2.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. using ARMeilleure.IntermediateRepresentation;
  2. using ARMeilleure.Translation;
  3. using static ARMeilleure.IntermediateRepresentation.Operation.Factory;
  4. namespace ARMeilleure.CodeGen.Optimizations
  5. {
  6. static class TailMerge
  7. {
  8. public static void RunPass(in CompilerContext cctx)
  9. {
  10. ControlFlowGraph cfg = cctx.Cfg;
  11. BasicBlock mergedReturn = new(cfg.Blocks.Count);
  12. Operand returnValue;
  13. Operation returnOp;
  14. if (cctx.FuncReturnType == OperandType.None)
  15. {
  16. returnValue = default;
  17. returnOp = Operation(Instruction.Return, default);
  18. }
  19. else
  20. {
  21. returnValue = cfg.AllocateLocal(cctx.FuncReturnType);
  22. returnOp = Operation(Instruction.Return, default, returnValue);
  23. }
  24. mergedReturn.Frequency = BasicBlockFrequency.Cold;
  25. mergedReturn.Operations.AddLast(returnOp);
  26. for (BasicBlock block = cfg.Blocks.First; block != null; block = block.ListNext)
  27. {
  28. Operation op = block.Operations.Last;
  29. if (op != default && op.Instruction == Instruction.Return)
  30. {
  31. block.Operations.Remove(op);
  32. if (cctx.FuncReturnType == OperandType.None)
  33. {
  34. PrepareMerge(block, mergedReturn);
  35. }
  36. else
  37. {
  38. Operation copyOp = Operation(Instruction.Copy, returnValue, op.GetSource(0));
  39. PrepareMerge(block, mergedReturn).Append(copyOp);
  40. }
  41. }
  42. }
  43. cfg.Blocks.AddLast(mergedReturn);
  44. cfg.Update();
  45. }
  46. private static BasicBlock PrepareMerge(BasicBlock from, BasicBlock to)
  47. {
  48. BasicBlock fromPred = from.Predecessors.Count == 1 ? from.Predecessors[0] : null;
  49. // If the block is empty, we can try to append to the predecessor and avoid unnecessary jumps.
  50. if (from.Operations.Count == 0 && fromPred != null && fromPred.SuccessorsCount == 1)
  51. {
  52. for (int i = 0; i < fromPred.SuccessorsCount; i++)
  53. {
  54. if (fromPred.GetSuccessor(i) == from)
  55. {
  56. fromPred.SetSuccessor(i, to);
  57. }
  58. }
  59. // NOTE: `from` becomes unreachable and the call to `cfg.Update()` will remove it.
  60. return fromPred;
  61. }
  62. else
  63. {
  64. from.AddSuccessor(to);
  65. return from;
  66. }
  67. }
  68. }
  69. }