Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
144 changes: 144 additions & 0 deletions src/Lua/CodeAnalysis/Compilation/FunctionCompilationContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,150 @@ public void PushInstruction(in Instruction instruction, in SourcePosition positi
instructionPositions.Add(position);
}

/// <summary>
/// Push or merge the new instruction.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PushOrMergeInstruction(int lastLocal, in Instruction instruction, in SourcePosition position, ref bool incrementStackPosition)
{
if (instructions.Length == 0)
{
instructions.Add(instruction);
instructionPositions.Add(position);
return;
}
ref var lastInstruction = ref instructions.AsSpan()[^1];
var opcode = instruction.OpCode;
switch (opcode)
{
case OpCode.Move:
// last A is not local variable
if (lastInstruction.A != lastLocal &&
// available to merge
lastInstruction.A == instruction.B &&
// not already merged
lastInstruction.A != lastInstruction.B)
{
switch (lastInstruction.OpCode)
{
case OpCode.GetTable:
case OpCode.Add:
case OpCode.Sub:
case OpCode.Mul:
case OpCode.Div:
case OpCode.Mod:
case OpCode.Pow:
case OpCode.Concat:
{
lastInstruction.A = instruction.A;
incrementStackPosition = false;
return;
}
}
}
break;
case OpCode.GetTable:
{
// Merge MOVE GetTable
if (lastInstruction.OpCode == OpCode.Move && lastLocal != lastInstruction.A)
{
if (lastInstruction.A == instruction.B)
{
lastInstruction = Instruction.GetTable(instruction.A, lastInstruction.B, instruction.C);
instructionPositions[^1] = position;
incrementStackPosition = false;
return;
}

}
break;
}
case OpCode.SetTable:
{
// Merge MOVE SETTABLE
if (lastInstruction.OpCode == OpCode.Move && lastLocal != lastInstruction.A)
{
var lastB = lastInstruction.B;
var lastA = lastInstruction.A;
if (lastB < 255 && lastA == instruction.A)
{
// Merge MOVE MOVE SETTABLE
if (instructions.Length > 2)
{
ref var last2Instruction = ref instructions.AsSpan()[^2];
var last2A = last2Instruction.A;
if (last2Instruction.OpCode == OpCode.Move && lastLocal != last2A && instruction.C == last2A)
{
last2Instruction = Instruction.SetTable((byte)(lastB), instruction.B, last2Instruction.B);
instructions.RemoveAtSwapback(instructions.Length - 1);
instructionPositions.RemoveAtSwapback(instructionPositions.Length - 1);
instructionPositions[^1] = position;
incrementStackPosition = false;
return;
}
}
lastInstruction = Instruction.SetTable((byte)(lastB), instruction.B, instruction.C);
instructionPositions[^1] = position;
incrementStackPosition = false;
return;
}

if (lastA == instruction.C)
{
lastInstruction = Instruction.SetTable(instruction.A, instruction.B, lastB);
instructionPositions[^1] = position;
incrementStackPosition = false;
return;
}
}
else if (lastInstruction.OpCode == OpCode.GetTabUp && instructions.Length >= 2)
{
ref var last2Instruction = ref instructions[^2];
var last2OpCode = last2Instruction.OpCode;
if (last2OpCode is OpCode.LoadK or OpCode.Move)
{

var last2A = last2Instruction.A;
if (last2A != lastLocal && instruction.C == last2A)
{
var c = last2OpCode == OpCode.LoadK ? last2Instruction.Bx + 256 : last2Instruction.B;
last2Instruction = lastInstruction;
lastInstruction = instruction with { C = (ushort)c };
instructionPositions[^2] = instructionPositions[^1];
instructionPositions[^1] = position;
incrementStackPosition = false;
return;
}
}
}
break;
}
case OpCode.Unm:
case OpCode.Not:
case OpCode.Len:
if (lastInstruction.OpCode == OpCode.Move && lastLocal != lastInstruction.A && lastInstruction.A == instruction.B)
{
lastInstruction = instruction with { B = lastInstruction.B }; ;
instructionPositions[^1] = position;
incrementStackPosition = false;
return;
}
break;
case OpCode.Return:
if (lastInstruction.OpCode == OpCode.Move && instruction.B == 2 && lastInstruction.B < 256)
{
lastInstruction = instruction with { A = (byte)lastInstruction.B };
instructionPositions[^1] = position;
incrementStackPosition = false;
return;
}
break;
}

instructions.Add(instruction);
instructionPositions.Add(position);
}

/// <summary>
/// Gets the index of the constant from the value, or if the constant is not registered it is added and its index is returned.
/// </summary>
Expand Down
14 changes: 11 additions & 3 deletions src/Lua/CodeAnalysis/Compilation/ScopeCompilationContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ public static void Return(ScopeCompilationContext context)
readonly Dictionary<ReadOnlyMemory<char>, LocalVariableDescription> localVariables = new(256, Utf16StringMemoryComparer.Default);
readonly Dictionary<ReadOnlyMemory<char>, LabelDescription> labels = new(32, Utf16StringMemoryComparer.Default);

byte lastLocalVariableIndex;

public byte StackStartPosition { get; private set; }
public byte StackPosition { get; set; }

Expand Down Expand Up @@ -72,8 +74,11 @@ public FunctionCompilationContext CreateChildFunction()
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PushInstruction(in Instruction instruction, SourcePosition position, bool incrementStackPosition = false)
{
Function.PushInstruction(instruction, position);
if (incrementStackPosition) StackPosition++;
Function.PushOrMergeInstruction(lastLocalVariableIndex, instruction, position, ref incrementStackPosition);
if (incrementStackPosition)
{
StackPosition++;
}
}

[MethodImpl(MethodImplOptions.AggressiveInlining)]
Expand All @@ -89,11 +94,13 @@ public void TryPushCloseUpValue(byte top, SourcePosition position)
/// Add new local variable.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void AddLocalVariable(ReadOnlyMemory<char> name, LocalVariableDescription description)
public void AddLocalVariable(ReadOnlyMemory<char> name, LocalVariableDescription description, bool markAsLastLocalVariable = true)
{
localVariables[name] = description;
lastLocalVariableIndex = description.RegisterIndex;
}


/// <summary>
/// Gets the local variable in scope.
/// </summary>
Expand Down Expand Up @@ -157,6 +164,7 @@ public void Reset()
HasCapturedLocalVariables = false;
localVariables.Clear();
labels.Clear();
lastLocalVariableIndex = 0;
}

/// <summary>
Expand Down