aboutsummaryrefslogtreecommitdiff
path: root/src/ARMeilleure/IntermediateRepresentation/BasicBlock.cs
blob: 810461d7c01c91b4999dda8955873061a636f9bb (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;

namespace ARMeilleure.IntermediateRepresentation
{
    class BasicBlock : IEquatable<BasicBlock>, IIntrusiveListNode<BasicBlock>
    {
        private const uint MaxSuccessors = 2;

        private int _succCount;
        private BasicBlock _succ0;
        private readonly BasicBlock _succ1;
        private HashSet<BasicBlock> _domFrontiers;

        public int Index { get; set; }
        public BasicBlockFrequency Frequency { get; set; }
        public BasicBlock ListPrevious { get; set; }
        public BasicBlock ListNext { get; set; }
        public IntrusiveList<Operation> Operations { get; }
        public List<BasicBlock> Predecessors { get; }
        public BasicBlock ImmediateDominator { get; set; }

        public int SuccessorsCount => _succCount;

        public HashSet<BasicBlock> DominanceFrontiers
        {
            get
            {
                _domFrontiers ??= new HashSet<BasicBlock>();

                return _domFrontiers;
            }
        }

        public BasicBlock() : this(index: -1) { }

        public BasicBlock(int index)
        {
            Operations = new IntrusiveList<Operation>();
            Predecessors = new List<BasicBlock>();

            Index = index;
        }

        public void AddSuccessor(BasicBlock block)
        {
            ArgumentNullException.ThrowIfNull(block);

            if ((uint)_succCount + 1 > MaxSuccessors)
            {
                ThrowSuccessorOverflow();
            }

            block.Predecessors.Add(this);

            GetSuccessorUnsafe(_succCount++) = block;
        }

        public void RemoveSuccessor(int index)
        {
            if ((uint)index >= (uint)_succCount)
            {
                ThrowOutOfRange(nameof(index));
            }

            ref BasicBlock oldBlock = ref GetSuccessorUnsafe(index);

            oldBlock.Predecessors.Remove(this);
            oldBlock = null;

            if (index == 0)
            {
                _succ0 = _succ1;
            }

            _succCount--;
        }

        public BasicBlock GetSuccessor(int index)
        {
            if ((uint)index >= (uint)_succCount)
            {
                ThrowOutOfRange(nameof(index));
            }

            return GetSuccessorUnsafe(index);
        }

        private ref BasicBlock GetSuccessorUnsafe(int index)
        {
            return ref Unsafe.Add(ref _succ0, index);
        }

        public void SetSuccessor(int index, BasicBlock block)
        {
            ArgumentNullException.ThrowIfNull(block);

            if ((uint)index >= (uint)_succCount)
            {
                ThrowOutOfRange(nameof(index));
            }

            ref BasicBlock oldBlock = ref GetSuccessorUnsafe(index);

            oldBlock.Predecessors.Remove(this);
            block.Predecessors.Add(this);

            oldBlock = block;
        }

        public void Append(Operation node)
        {
            Operation last = Operations.Last;

            // Append node before terminal or to end if no terminal.
            if (last == default)
            {
                Operations.AddLast(node);

                return;
            }

            switch (last.Instruction)
            {
                case Instruction.Return:
                case Instruction.Tailcall:
                case Instruction.BranchIf:
                    Operations.AddBefore(last, node);
                    break;

                default:
                    Operations.AddLast(node);
                    break;
            }
        }

        private static void ThrowOutOfRange(string name) => throw new ArgumentOutOfRangeException(name);
        private static void ThrowSuccessorOverflow() => throw new OverflowException($"BasicBlock can only have {MaxSuccessors} successors.");

        public bool Equals(BasicBlock other)
        {
            return other == this;
        }

        public override bool Equals(object obj)
        {
            return Equals(obj as BasicBlock);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
    }
}