• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

SamboyCoding / Cpp2IL / 17101091060

20 Aug 2025 02:16PM UTC coverage: 30.421% (-3.9%) from 34.352%
17101091060

Pull #481

github

web-flow
Merge 42542dde2 into d5260685f
Pull Request #481: Decompiler

1804 of 7551 branches covered (23.89%)

Branch coverage included in aggregate %.

102 of 1827 new or added lines in 35 files covered. (5.58%)

40 existing lines in 6 files now uncovered.

4095 of 11840 relevant lines covered (34.59%)

165714.86 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/Cpp2IL.Core/Actions/BuildSsaForm.cs
1
using System.Collections.Generic;
2
using System.Linq;
3
using Cpp2IL.Core.Graphs;
4
using Cpp2IL.Core.ISIL;
5
using Cpp2IL.Core.Model.Contexts;
6

7
namespace Cpp2IL.Core.Actions;
8

9
public class BuildSsaForm : IAction
10
{
NEW
11
    private Dictionary<int, Stack<Register>> _versions = new();
×
NEW
12
    private Dictionary<int, int> _versionCount = new();
×
NEW
13
    private Dictionary<Block, Dictionary<int, Register>> _blockOutVersions = new();
×
14

15
    public void Apply(MethodAnalysisContext method)
16
    {
NEW
17
        method.ControlFlowGraph!.BuildUseDefLists();
×
18

NEW
19
        _versions.Clear();
×
NEW
20
        _versionCount.Clear();
×
NEW
21
        _blockOutVersions.Clear();
×
22

NEW
23
        var graph = method.ControlFlowGraph!;
×
NEW
24
        var dominatorInfo = method.DominatorInfo!;
×
25

NEW
26
        ProcessBlock(graph.EntryBlock, dominatorInfo.DominanceTree);
×
NEW
27
        InsertAllPhiFunctions(graph, dominatorInfo, method.ParameterOperands);
×
NEW
28
    }
×
29

30
    private void InsertAllPhiFunctions(ISILControlFlowGraph graph, DominatorInfo dominance, List<object> parameters)
31
    {
32
        // Check where registers are defined
NEW
33
        var defSites = GetDefinitionSites(graph);
×
34

35
        // For each register
NEW
36
        foreach (var entry in defSites)
×
37
        {
NEW
38
            var regNumber = entry.Key;
×
39

NEW
40
            var workList = new Queue<Block>(entry.Value);
×
NEW
41
            var phiInserted = new HashSet<Block>();
×
42

NEW
43
            while (workList.Count > 0)
×
44
            {
NEW
45
                var block = workList.Dequeue();
×
46

47
                // For each dominance frontier block of the current block
NEW
48
                if (!dominance.DominanceFrontier.TryGetValue(block, out var dfBlocks))
×
49
                    continue;
50

NEW
51
                foreach (var dfBlock in dfBlocks)
×
52
                {
53
                    // Already visited
NEW
54
                    if (phiInserted.Contains(dfBlock)) continue;
×
55

56
                    // For each predecessor, get it's last register version
NEW
57
                    var sources = new List<Register>();
×
NEW
58
                    foreach (var pred in dfBlock.Predecessors)
×
59
                    {
NEW
60
                        if (_blockOutVersions.TryGetValue(pred, out var mapping)
×
NEW
61
                            && mapping.TryGetValue(regNumber, out var versionedReg))
×
62
                        {
NEW
63
                            sources.Add(versionedReg);
×
64
                        }
65
                        else
66
                        {
67
                            // It's not in predecessors so it's probably a parameter
NEW
68
                            var param = parameters.OfType<Register>().FirstOrDefault(p => p.Number == regNumber);
×
NEW
69
                            sources.Add(param);
×
70
                        }
71
                    }
72

73
                    // Insert phi into the frontier block
NEW
74
                    InsertPhiFunction(sources, dfBlock);
×
NEW
75
                    phiInserted.Add(dfBlock);
×
76

77
                    // If dfBlock doesn't define this register, add it to queue
NEW
78
                    var defines = dfBlock.Def.Any(operand => operand is Register r && r.Number == regNumber);
×
NEW
79
                    if (!defines)
×
NEW
80
                        workList.Enqueue(dfBlock);
×
81
                }
82
            }
83
        }
NEW
84
    }
×
85

86
    private static Dictionary<int, HashSet<Block>> GetDefinitionSites(ISILControlFlowGraph graph)
87
    {
88
        // Check what registers are defined and where
NEW
89
        var defSites = new Dictionary<int, HashSet<Block>>();
×
90

NEW
91
        foreach (var block in graph.Blocks)
×
92
        {
NEW
93
            for (var i = 0; i < block.Def.Count; i++)
×
94
            {
NEW
95
                var operand = block.Def[i];
×
96

NEW
97
                if (operand is Register register)
×
98
                {
NEW
99
                    if (!defSites.ContainsKey(register.Number))
×
NEW
100
                        defSites[register.Number] = [];
×
NEW
101
                    defSites[register.Number].Add(block);
×
102
                }
103
            }
104
        }
105

NEW
106
        return defSites;
×
107
    }
108

109
    private void InsertPhiFunction(List<Register> sources, Block block)
110
    {
111
        // Create phi dest, src1, src2, etc.
NEW
112
        var destination = GetNewVersion(sources[0]);
×
NEW
113
        var phi = new Instruction(-1, OpCode.Phi, destination);
×
114

NEW
115
        foreach (var source in sources.Distinct())
×
NEW
116
            phi.Operands.Add(source);
×
117

118
        // Add it
NEW
119
        block.Instructions.Insert(0, phi);
×
120
        // Replace uses
NEW
121
        ReplaceRegistersUntilReassignment(block, 1, destination);
×
NEW
122
    }
×
123

124
    private static void ReplaceRegistersUntilReassignment(Block block, int startIndex, Register register)
125
    {
NEW
126
        for (var i = startIndex; i < block.Instructions.Count; i++)
×
127
        {
NEW
128
            var instruction = block.Instructions[i];
×
129

130
            // Reassignment?
NEW
131
            if (instruction.Destination is Register destination)
×
132
            {
NEW
133
                if (destination.Number == register.Number)
×
NEW
134
                    return;
×
135
            }
136

137
            // Replace it
NEW
138
            for (var j = 0; j < instruction.Operands.Count; j++)
×
139
            {
NEW
140
                var operand = instruction.Operands[j];
×
141

NEW
142
                if (operand is Register register2)
×
143
                {
NEW
144
                    if (register2.Number == register.Number)
×
NEW
145
                        instruction.Operands[j] = register;
×
146
                }
147

NEW
148
                if (operand is MemoryOperand memory)
×
149
                {
NEW
150
                    if (memory.Base != null)
×
151
                    {
NEW
152
                        var baseRegister = (Register)memory.Base;
×
153

NEW
154
                        if (baseRegister.Number == register.Number)
×
NEW
155
                            memory.Base = register;
×
156
                    }
157

NEW
158
                    if (memory.Index != null)
×
159
                    {
NEW
160
                        var index = (Register)memory.Index;
×
161

NEW
162
                        if (index.Number == register.Number)
×
NEW
163
                            memory.Index = register;
×
164
                    }
165

NEW
166
                    instruction.Operands[j] = memory;
×
167
                }
168
            }
169
        }
NEW
170
    }
×
171

172
    private Register GetNewVersion(Register old)
173
    {
NEW
174
        if (!_versionCount.ContainsKey(old.Number))
×
175
        {
176
            // Params are version 0
NEW
177
            _versionCount.Add(old.Number, 0);
×
NEW
178
            _versions.Add(old.Number, new Stack<Register>());
×
NEW
179
            _versions[old.Number].Push(old.Copy(0));
×
180
        }
181

NEW
182
        _versionCount[old.Number]++;
×
NEW
183
        var newRegister = old.Copy(_versionCount[old.Number]);
×
NEW
184
        _versions[old.Number].Push(newRegister);
×
NEW
185
        return newRegister;
×
186
    }
187

188
    private void ProcessBlock(Block block, Dictionary<Block, List<Block>> dominanceTree)
189
    {
NEW
190
        foreach (var instruction in block.Instructions)
×
191
        {
192
            // Replace registers with SSA versions
NEW
193
            for (var i = 0; i < instruction.Operands.Count; i++)
×
194
            {
NEW
195
                if (instruction.Operands[i] is Register register)
×
196
                {
NEW
197
                    if (_versions.TryGetValue(register.Number, out var versions))
×
NEW
198
                        instruction.Operands[i] = register.Copy(versions.Peek().Version);
×
199
                }
200

NEW
201
                if (instruction.Operands[i] is MemoryOperand memory)
×
202
                {
NEW
203
                    if (memory.Base != null)
×
204
                    {
NEW
205
                        var baseRegister = (Register)memory.Base;
×
206

NEW
207
                        if (_versions.TryGetValue(baseRegister.Number, out var versions))
×
NEW
208
                            memory.Base = baseRegister.Copy(versions.Peek().Version);
×
209
                    }
210

NEW
211
                    if (memory.Index != null)
×
212
                    {
NEW
213
                        var indexRegister = (Register)memory.Index;
×
214

NEW
215
                        if (_versions.TryGetValue(indexRegister.Number, out var versions))
×
NEW
216
                            memory.Index = indexRegister.Copy(versions.Peek().Version);
×
217
                    }
218

NEW
219
                    instruction.Operands[i] = memory;
×
220
                }
221
            }
222

223
            // Create new version
NEW
224
            if (instruction.Destination is Register destination)
×
NEW
225
                instruction.Destination = GetNewVersion(destination);
×
226
        }
227

228
        // Record last register version
NEW
229
        var outMapping = new Dictionary<int, Register>();
×
NEW
230
        foreach (var kvp in _versions)
×
231
        {
NEW
232
            if (kvp.Value.Count > 0)
×
NEW
233
                outMapping[kvp.Key] = kvp.Value.Peek();
×
234
        }
235

NEW
236
        _blockOutVersions[block] = outMapping;
×
237

238
        // Process children in the tree
NEW
239
        if (dominanceTree.TryGetValue(block, out var children))
×
240
        {
NEW
241
            foreach (var child in children)
×
NEW
242
                ProcessBlock(child, dominanceTree);
×
243
        }
244

245
        // Remove registers from versions but not from count
NEW
246
        foreach (var instruction in block.Instructions.Where(i => i.Destination is Register))
×
247
        {
NEW
248
            var register = (Register)instruction.Destination!;
×
NEW
249
            _versions.FirstOrDefault(kv => kv.Key == register.Number).Value.Pop();
×
250
        }
NEW
251
    }
×
252
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc