aboutsummaryrefslogtreecommitdiff
path: root/ChocolArm64/IntermediateRepresentation/BasicBlock.cs
blob: ce39fddba8045971b85bd65725a45c28aa0dec14 (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
using ChocolArm64.State;
using System;
using System.Collections.Generic;

using static ChocolArm64.State.RegisterConsts;

namespace ChocolArm64.IntermediateRepresentation
{
    class BasicBlock
    {
        public int Index { get; set; }

        public RegisterMask RegInputs  { get; private set; }
        public RegisterMask RegOutputs { get; private set; }

        public bool HasStateLoad { get; private set; }

        private List<Operation> _operations;

        public int Count => _operations.Count;

        private BasicBlock _next;
        private BasicBlock _branch;

        public BasicBlock Next
        {
            get => _next;
            set => _next = AddSuccessor(_next, value);
        }

        public BasicBlock Branch
        {
            get => _branch;
            set => _branch = AddSuccessor(_branch, value);
        }

        public List<BasicBlock> Predecessors { get; }

        public BasicBlock(int index = 0)
        {
            Index = index;

            _operations = new List<Operation>();

            Predecessors = new List<BasicBlock>();
        }

        private BasicBlock AddSuccessor(BasicBlock oldBlock, BasicBlock newBlock)
        {
            oldBlock?.Predecessors.Remove(this);
            newBlock?.Predecessors.Add(this);

            return newBlock;
        }

        public void Add(Operation operation)
        {
            if (operation.Type == OperationType.LoadLocal ||
                operation.Type == OperationType.StoreLocal)
            {
                int index = operation.GetArg<int>(0);

                if (IsRegIndex(index))
                {
                    long intMask = 0;
                    long vecMask = 0;

                    switch (operation.GetArg<RegisterType>(1))
                    {
                        case RegisterType.Flag:   intMask = (1L << RegsCount) << index; break;
                        case RegisterType.Int:    intMask =  1L               << index; break;
                        case RegisterType.Vector: vecMask =  1L               << index; break;
                    }

                    RegisterMask mask = new RegisterMask(intMask, vecMask);

                    if (operation.Type == OperationType.LoadLocal)
                    {
                        RegInputs |= mask & ~RegOutputs;
                    }
                    else
                    {
                        RegOutputs |= mask;
                    }
                }
            }
            else if (operation.Type == OperationType.LoadContext)
            {
                HasStateLoad = true;
            }

            operation.Parent = this;

            _operations.Add(operation);
        }

        public static bool IsRegIndex(int index)
        {
            return (uint)index < RegsCount;
        }

        public Operation GetOperation(int index)
        {
            if ((uint)index >= _operations.Count)
            {
                throw new ArgumentOutOfRangeException(nameof(index));
            }

            return _operations[index];
        }

        public Operation GetLastOp()
        {
            if (Count == 0)
            {
                return null;
            }

            return _operations[Count - 1];
        }
    }
}