Skip to content

Commit

Permalink
Merge branch 'localloc_support'
Browse files Browse the repository at this point in the history
  • Loading branch information
Anton92nd committed May 23, 2020
2 parents c6c133a + 01249ea commit 1815018
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 0 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Changelog

## v3.3.X - 2020.05.23
- Support `Localloc` operation

## v3.3.1 - 2020.04.01
- Sign GrEmit assembly with strong name

Expand Down
85 changes: 85 additions & 0 deletions GrEmit.Tests/Test.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,91 @@ namespace GrEmit.Tests
[TestFixture]
public class Test
{
[Test]
public void TestLocalloc()
{
// private static unsafe int GetSum(byte length)
// {
// byte* bytes = stackalloc byte[length];
// for (byte i = 0; i < length; ++i)
// {
// bytes[i] = i;
// }
// int sum = 0;
// for (byte i = 0; i < length; ++i)
// {
// sum += bytes[i];
// }
// return sum;
// }
var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(int), new[] {typeof(byte)}, typeof(Test));
using (var il = new GroboIL(method))
{
il.Ldarg(0); // stack: [length]
il.Conv<UIntPtr>();
il.Localloc(); // stack: [*pointer]
var pointer = il.DeclareLocal(typeof(UIntPtr));
il.Stloc(pointer); // pointer = value; stack: []

il.Ldc_I4(0); // stack: [0]
var i = il.DeclareLocal(typeof(byte));
il.Stloc(i); // i = 0; stack: []
var loop1Start = il.DefineLabel("loop1_start");
var loop1End = il.DefineLabel("loop1_end");
il.MarkLabel(loop1Start);
{
il.Ldloc(i); // stack: [i]
il.Ldarg(0); // stack: [i, length]
il.Bge(loop1End, unsigned : true); // if (i >= length) goto end; stack: []
il.Ldloc(pointer); //stack: [pointer]
il.Ldloc(i); // stack: [pointer, i]
il.Add(); // stack: [pointer + i]
il.Ldloc(i); // stack: [pointer + i, i]
il.Stind(typeof(byte)); // *(pointer + i) = i; stack: []
il.Ldloc(i); // stack: [i]
il.Ldc_I4(1); // stack: [i, 1]
il.Add(); // stack: [i + 1]
il.Conv<byte>();
il.Stloc(i); // i = i + 1; stack: []
il.Br(loop1Start);
}
il.MarkLabel(loop1End);

il.Ldc_I4(0); // stack: [0]
il.Dup(); // stack: [0, 0]
var sum = il.DeclareLocal(typeof(int));
il.Stloc(sum); // sum = 0; stack: [0]
il.Stloc(i); // i = 0; stack: []
var loop2Start = il.DefineLabel("loop2_start");
var loop2End = il.DefineLabel("loop2_end");
il.MarkLabel(loop2Start);
{
il.Ldloc(i); // stack: [i]
il.Ldarg(0); // stack: [i, length]
il.Bge(loop2End, unsigned : true); // if i >= length goto end; stack:[]
il.Ldloc(pointer); // stack: [pointer]
il.Ldloc(i); // stack: [pointer, i]
il.Add(); // stack: [pointer + i]
il.Ldind(typeof(byte)); // stack: [*(pointer + i)]
il.Ldloc(sum); // stack: [*(pointer + i), sum]
il.Add(); // stack: [*(pointer + i) + sum]
il.Stloc(sum); // sum = *(pointer + i) + sum; stack: []
il.Ldloc(i); // stack: [i]
il.Ldc_I4(1); // stack: [i, 1]
il.Add(); // stack: [i + 1]
il.Conv<byte>();
il.Stloc(i); // i = (i + 1); // stack: []
il.Br(loop2Start);
}
il.MarkLabel(loop2End);

il.Ldloc(sum); // stack: [sum]
il.Ret();
}
var func = (Func<byte, int>)method.CreateDelegate(typeof(Func<byte, int>));
Assert.That(func(6), Is.EqualTo(15));
}

[Test]
public void TestDifferentStructs()
{
Expand Down
5 changes: 5 additions & 0 deletions GrEmit/GroboIL.cs
Original file line number Diff line number Diff line change
Expand Up @@ -925,6 +925,11 @@ public void Ldc_IntPtr(IntPtr value)
Conv<IntPtr>();
}

public void Localloc()
{
Emit(OpCodes.Localloc);
}

/// <summary>
/// Clears the specified pinned local by setting it to null
/// </summary>
Expand Down
1 change: 1 addition & 0 deletions GrEmit/StackMutatorCollection.cs
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ public static void Mutate(OpCode opCode, GroboIL il, ILInstructionParameter para
{OpCodes.Stelem_R8, new StelemStackMutator()},
{OpCodes.Stelem_Ref, new StelemStackMutator()},
{OpCodes.Ckfinite, new CkfiniteStackMutator()},
{OpCodes.Localloc, new LocallocStackMutator()},
};

private static readonly MarkLabelStackMutator markLabelStackMutator = new MarkLabelStackMutator();
Expand Down
16 changes: 16 additions & 0 deletions GrEmit/StackMutators/LocallocStackMutator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System;

namespace GrEmit.StackMutators
{
internal class LocallocStackMutator : StackMutator
{
public override void Mutate(GroboIL il, ILInstructionParameter parameter, ref EvaluationStack stack)
{
CheckNotEmpty(il, stack, () => $"In order to perform the instruction 'localloc' size must be loaded onto the evaluation stack");
var type = stack.Pop();
if (ToCLIType(type) != CLIType.NativeInt)
ThrowError(il, $"Unable to perform the instruction 'localloc' on type '{type}'");
stack.Push(typeof(UIntPtr));
}
}
}

0 comments on commit 1815018

Please sign in to comment.