Turn block_return into IR instruction

This commit is contained in:
HoLLy 2019-11-23 21:26:27 +01:00
Родитель ff92ec08d7
Коммит 53750f7332
3 изменённых файлов: 33 добавлений и 11 удалений

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

@ -0,0 +1,21 @@
using WasmLib.FileFormat;
namespace WasmLib.Decompilation.Intermediate.Instructions
{
public class BlockReturnInstruction : IntermediateInstruction
{
private readonly ValueKind type;
public BlockReturnInstruction(ValueKind type)
{
this.type = type;
}
public override ValueKind[] PopTypes => new[] {type};
public override ValueKind[] PushTypes => new ValueKind[0];
public override bool RestOfBlockUnreachable => true;
public override bool IsPure => false;
public override string OperationStringFormat => "block_return {0}";
}
}

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

@ -33,15 +33,19 @@ namespace WasmLib.Decompilation.Intermediate
return block;
}
private List<IntermediateInstruction> ConvertBlock(ref int i, bool allowElse = false)
private List<IntermediateInstruction> ConvertBlock(ref int i, bool allowElse = false, ValueKind blockReturnType = ValueKind.Empty)
{
var list = new List<IntermediateInstruction>();
bool reachable = true;
for (; i < function.Instructions.Length; i++) {
Instruction instruction = function.Instructions[i];
switch (instruction.OpCode) {
case OpCode.End:
case OpCode.Else when allowElse:
if (blockReturnType != ValueKind.Empty && reachable) {
list.Add(new BlockReturnInstruction(blockReturnType));
}
return list;
case OpCode.Else:
throw new Exception($"Unexpected `{instruction}` instruction, else is not allowed in the current block");
@ -49,13 +53,13 @@ namespace WasmLib.Decompilation.Intermediate
case OpCode.Loop:
case OpCode.If:
i++;
List<IntermediateInstruction> list1 = ConvertBlock(ref i, instruction.OpCode == OpCode.If);
List<IntermediateInstruction> list1 = ConvertBlock(ref i, instruction.OpCode == OpCode.If, (ValueKind)instruction.UIntOperand);
List<IntermediateInstruction>? list2 = null;
var instr = function.Instructions[i];
if (instr.OpCode == OpCode.Else) {
i++;
list2 = ConvertBlock(ref i);
list2 = ConvertBlock(ref i, false, (ValueKind)instruction.UIntOperand);
}
else {
Debug.Assert(instr.OpCode == OpCode.End);
@ -68,6 +72,10 @@ namespace WasmLib.Decompilation.Intermediate
if (intermediateInstruction != null) {
list.Add(intermediateInstruction);
if (intermediateInstruction.RestOfBlockUnreachable) {
reachable = false;
}
}
break;

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

@ -102,14 +102,7 @@ namespace WasmLib.Decompilation
HandleInstruction(ref context2, instr);
}
// if stack has values left on it, and we expect a return value
if (block.HasReturn && !context2.RestOfBlockUnreachable) {
Debug.Assert(context2.StackIndices.Peek() != context2.Stack.Count);
var popped = context2.Pop();
Debug.Assert(popped.Type == block.ValueKind);
context2.WriteFull($"block_return {popped}");
}
Debug.Assert(!(block.HasReturn && !context2.RestOfBlockUnreachable));
context2.ExitBlock();
}