aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Cpu/LightningJit/Arm32/Block.cs
blob: c4568995c507d97f2b12f473b40826a08c2970be (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
using System.Collections.Generic;
using System.Diagnostics;

namespace Ryujinx.Cpu.LightningJit.Arm32
{
    class Block
    {
        public readonly ulong Address;
        public readonly ulong EndAddress;
        public readonly List<InstInfo> Instructions;
        public readonly bool EndsWithBranch;
        public readonly bool HasHostCall;
        public readonly bool HasHostCallSkipContext;
        public readonly bool IsTruncated;
        public readonly bool IsLoopEnd;
        public readonly bool IsThumb;

        public Block(
            ulong address,
            ulong endAddress,
            List<InstInfo> instructions,
            bool endsWithBranch,
            bool hasHostCall,
            bool hasHostCallSkipContext,
            bool isTruncated,
            bool isLoopEnd,
            bool isThumb)
        {
            Debug.Assert(isThumb || (int)((endAddress - address) / 4) == instructions.Count);

            Address = address;
            EndAddress = endAddress;
            Instructions = instructions;
            EndsWithBranch = endsWithBranch;
            HasHostCall = hasHostCall;
            HasHostCallSkipContext = hasHostCallSkipContext;
            IsTruncated = isTruncated;
            IsLoopEnd = isLoopEnd;
            IsThumb = isThumb;
        }

        public (Block, Block) SplitAtAddress(ulong address)
        {
            int splitIndex = FindSplitIndex(address);

            if (splitIndex < 0)
            {
                return (null, null);
            }

            int splitCount = Instructions.Count - splitIndex;

            // Technically those are valid, but we don't want to create empty blocks.
            Debug.Assert(splitIndex != 0);
            Debug.Assert(splitCount != 0);

            Block leftBlock = new(
                Address,
                address,
                Instructions.GetRange(0, splitIndex),
                false,
                HasHostCall,
                HasHostCallSkipContext,
                false,
                false,
                IsThumb);

            Block rightBlock = new(
                address,
                EndAddress,
                Instructions.GetRange(splitIndex, splitCount),
                EndsWithBranch,
                HasHostCall,
                HasHostCallSkipContext,
                IsTruncated,
                IsLoopEnd,
                IsThumb);

            return (leftBlock, rightBlock);
        }

        private int FindSplitIndex(ulong address)
        {
            if (IsThumb)
            {
                ulong pc = Address;

                for (int index = 0; index < Instructions.Count; index++)
                {
                    if (pc == address)
                    {
                        return index;
                    }

                    pc += Instructions[index].Flags.HasFlag(InstFlags.Thumb16) ? 2UL : 4UL;
                }

                return -1;
            }
            else
            {
                return (int)((address - Address) / 4);
            }
        }
    }
}