Implement basic control block support

This commit is contained in:
HoLLy 2019-11-23 17:08:33 +01:00
Родитель 1205ecb5cb
Коммит ff92ec08d7
3 изменённых файлов: 42 добавлений и 13 удалений

Просмотреть файл

@ -5,6 +5,7 @@ using System.IO;
using System.Linq;
using Rivers;
using Rivers.Analysis;
using Rivers.Serialization.Dot;
using WasmLib.Decompilation.Intermediate;
using WasmLib.Decompilation.Intermediate.Graph;
using WasmLib.Decompilation.SourceCode;
@ -49,17 +50,18 @@ namespace WasmLib.Decompilation
int instructionNum = 0;
foreach (IntermediateInstruction instruction in instructions) {
if (instruction.HasBlock) {
throw new NotImplementedException();
}
InstructionNode node = new InstructionNode(instruction, instructionNum++);
InstructionNode node = !instruction.HasBlock
? new InstructionNode(instruction, instructionNum++)
: instruction.Block2 == null
? new InstructionNode(instruction, instructionNum++, CreateGraph(instruction.Block1!.Instructions))
: new InstructionNode(instruction, instructionNum++, CreateGraph(instruction.Block1!.Instructions), CreateGraph(instruction.Block2.Instructions));
graph.Nodes.Add(node);
Debug.Assert(instruction.PushCount <= 1, "Instruction pushed multiple variables to stack, which shouldn't happen.");
for (int i = 0; i < instruction.PopCount; i++) {
(InstructionNode sourceInstruction, ValueKind type) = stack.Pop();
Debug.Assert(type == instruction.PopTypes[i]);
Debug.Assert(type == instruction.PopTypes[i] || type == ValueKind.Any || instruction.PopTypes[i] == ValueKind.Any);
sourceInstruction.OutgoingEdges.Add(new StackVariableEdge(sourceInstruction, node, type));
}
@ -79,13 +81,16 @@ namespace WasmLib.Decompilation
// BUG: see Washi1337/Rivers#6
// Debug.Assert(!graph.IsCyclic(), "Got cyclic dependency in function!");
if (!graph.IsConnected()) {
#if DEBUG
using (StreamWriter sw = new StreamWriter(File.OpenWrite("temp_unconnected.dot"))) new DotWriter(sw).Write(graph);
#endif
throw new NotImplementedException();
}
return graph;
}
private static void OutputAsCode(Graph graph, TextWriter output)
private static void OutputAsCode(Graph graph, TextWriter output, int tabCount = 1)
{
var varCounts = new Dictionary<ValueKind, int> {
{ValueKind.I32, 0},
@ -120,17 +125,32 @@ namespace WasmLib.Decompilation
}
}
statements[currentNode.Index] = new GenericExpression(currentNode.Instruction, parameters);
statements[currentNode.Index] = new GenericExpression(currentNode.Instruction, parameters, currentNode.Block1, currentNode.Block2);
}
else {
statements[currentNode.Index] = new GenericExpression(currentNode.Instruction);
statements[currentNode.Index] = new GenericExpression(currentNode.Instruction, null, currentNode.Block1, currentNode.Block2);
}
}
foreach (IExpression expression in statements.Values) {
// TODO: support comments
output.WriteLine(new string('\t', 1) + expression.GetStringRepresentation());
if (expression is GenericExpression ge && ge.Block1 != null) {
output.WriteLine(new string('\t', tabCount) + expression.GetStringRepresentation() + " {");
OutputAsCode(ge.Block1, output, tabCount + 1);
if (ge.Block2 == null) {
output.WriteLine(new string('\t', tabCount) + "}");
}
else {
output.WriteLine(new string('\t', tabCount) + "} else {");
OutputAsCode(ge.Block2, output, tabCount + 1);
output.WriteLine(new string('\t', tabCount) + "}");
}
}
else {
output.WriteLine(new string('\t', tabCount) + expression.GetStringRepresentation());
}
}
}
}

Просмотреть файл

@ -15,11 +15,15 @@ namespace WasmLib.Decompilation.Intermediate.Graph
public IEnumerable<ImpurityDependencyEdge> IncomingImpurityEdges => IncomingEdges.OfType<ImpurityDependencyEdge>();
public IEnumerable<StackVariableEdge> OutgoingVariableEdges => OutgoingEdges.OfType<StackVariableEdge>();
public IEnumerable<StackVariableEdge> IncomingVariableEdges => IncomingEdges.OfType<StackVariableEdge>();
public Rivers.Graph? Block1 { get; }
public Rivers.Graph? Block2 { get; }
public InstructionNode(IntermediateInstruction instruction, int idx) : base($"_{idx:X4}")
public InstructionNode(IntermediateInstruction instruction, int idx, Rivers.Graph? block1 = null, Rivers.Graph? block2 = null) : base($"_{idx:X4}")
{
Instruction = instruction;
Index = idx;
Block1 = block1;
Block2 = block2;
AddUserData();
}

Просмотреть файл

@ -1,4 +1,5 @@
using System.Linq;
using Rivers;
using WasmLib.Decompilation.Intermediate;
using WasmLib.Utils;
@ -8,11 +9,15 @@ namespace WasmLib.Decompilation.SourceCode
{
public IntermediateInstruction BaseInstruction { get; }
public IExpression[]? Parameters { get; }
public Graph? Block1 { get; }
public Graph? Block2 { get; }
public GenericExpression(IntermediateInstruction baseInstruction, IExpression[]? parameters = null)
public GenericExpression(IntermediateInstruction baseInstruction, IExpression[]? parameters = null, Graph? block1 = null, Graph? block2 = null)
{
BaseInstruction = baseInstruction;
Parameters = parameters;
Block1 = block1;
Block2 = block2;
}
public string GetStringRepresentation() => BaseInstruction.OperationStringFormat.SafeFormat(Parameters?.Select(x => x.GetStringRepresentation()).ToArray());