Turn block_return into IR instruction
This commit is contained in:
Родитель
ff92ec08d7
Коммит
53750f7332
|
@ -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();
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче