Skip to content

Commit 1815018

Browse files
committed
Merge branch 'localloc_support'
2 parents c6c133a + 01249ea commit 1815018

File tree

5 files changed

+110
-0
lines changed

5 files changed

+110
-0
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# Changelog
22

3+
## v3.3.X - 2020.05.23
4+
- Support `Localloc` operation
5+
36
## v3.3.1 - 2020.04.01
47
- Sign GrEmit assembly with strong name
58

GrEmit.Tests/Test.cs

+85
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,91 @@ namespace GrEmit.Tests
1818
[TestFixture]
1919
public class Test
2020
{
21+
[Test]
22+
public void TestLocalloc()
23+
{
24+
// private static unsafe int GetSum(byte length)
25+
// {
26+
// byte* bytes = stackalloc byte[length];
27+
// for (byte i = 0; i < length; ++i)
28+
// {
29+
// bytes[i] = i;
30+
// }
31+
// int sum = 0;
32+
// for (byte i = 0; i < length; ++i)
33+
// {
34+
// sum += bytes[i];
35+
// }
36+
// return sum;
37+
// }
38+
var method = new DynamicMethod(Guid.NewGuid().ToString(), typeof(int), new[] {typeof(byte)}, typeof(Test));
39+
using (var il = new GroboIL(method))
40+
{
41+
il.Ldarg(0); // stack: [length]
42+
il.Conv<UIntPtr>();
43+
il.Localloc(); // stack: [*pointer]
44+
var pointer = il.DeclareLocal(typeof(UIntPtr));
45+
il.Stloc(pointer); // pointer = value; stack: []
46+
47+
il.Ldc_I4(0); // stack: [0]
48+
var i = il.DeclareLocal(typeof(byte));
49+
il.Stloc(i); // i = 0; stack: []
50+
var loop1Start = il.DefineLabel("loop1_start");
51+
var loop1End = il.DefineLabel("loop1_end");
52+
il.MarkLabel(loop1Start);
53+
{
54+
il.Ldloc(i); // stack: [i]
55+
il.Ldarg(0); // stack: [i, length]
56+
il.Bge(loop1End, unsigned : true); // if (i >= length) goto end; stack: []
57+
il.Ldloc(pointer); //stack: [pointer]
58+
il.Ldloc(i); // stack: [pointer, i]
59+
il.Add(); // stack: [pointer + i]
60+
il.Ldloc(i); // stack: [pointer + i, i]
61+
il.Stind(typeof(byte)); // *(pointer + i) = i; stack: []
62+
il.Ldloc(i); // stack: [i]
63+
il.Ldc_I4(1); // stack: [i, 1]
64+
il.Add(); // stack: [i + 1]
65+
il.Conv<byte>();
66+
il.Stloc(i); // i = i + 1; stack: []
67+
il.Br(loop1Start);
68+
}
69+
il.MarkLabel(loop1End);
70+
71+
il.Ldc_I4(0); // stack: [0]
72+
il.Dup(); // stack: [0, 0]
73+
var sum = il.DeclareLocal(typeof(int));
74+
il.Stloc(sum); // sum = 0; stack: [0]
75+
il.Stloc(i); // i = 0; stack: []
76+
var loop2Start = il.DefineLabel("loop2_start");
77+
var loop2End = il.DefineLabel("loop2_end");
78+
il.MarkLabel(loop2Start);
79+
{
80+
il.Ldloc(i); // stack: [i]
81+
il.Ldarg(0); // stack: [i, length]
82+
il.Bge(loop2End, unsigned : true); // if i >= length goto end; stack:[]
83+
il.Ldloc(pointer); // stack: [pointer]
84+
il.Ldloc(i); // stack: [pointer, i]
85+
il.Add(); // stack: [pointer + i]
86+
il.Ldind(typeof(byte)); // stack: [*(pointer + i)]
87+
il.Ldloc(sum); // stack: [*(pointer + i), sum]
88+
il.Add(); // stack: [*(pointer + i) + sum]
89+
il.Stloc(sum); // sum = *(pointer + i) + sum; stack: []
90+
il.Ldloc(i); // stack: [i]
91+
il.Ldc_I4(1); // stack: [i, 1]
92+
il.Add(); // stack: [i + 1]
93+
il.Conv<byte>();
94+
il.Stloc(i); // i = (i + 1); // stack: []
95+
il.Br(loop2Start);
96+
}
97+
il.MarkLabel(loop2End);
98+
99+
il.Ldloc(sum); // stack: [sum]
100+
il.Ret();
101+
}
102+
var func = (Func<byte, int>)method.CreateDelegate(typeof(Func<byte, int>));
103+
Assert.That(func(6), Is.EqualTo(15));
104+
}
105+
21106
[Test]
22107
public void TestDifferentStructs()
23108
{

GrEmit/GroboIL.cs

+5
Original file line numberDiff line numberDiff line change
@@ -925,6 +925,11 @@ public void Ldc_IntPtr(IntPtr value)
925925
Conv<IntPtr>();
926926
}
927927

928+
public void Localloc()
929+
{
930+
Emit(OpCodes.Localloc);
931+
}
932+
928933
/// <summary>
929934
/// Clears the specified pinned local by setting it to null
930935
/// </summary>

GrEmit/StackMutatorCollection.cs

+1
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ public static void Mutate(OpCode opCode, GroboIL il, ILInstructionParameter para
210210
{OpCodes.Stelem_R8, new StelemStackMutator()},
211211
{OpCodes.Stelem_Ref, new StelemStackMutator()},
212212
{OpCodes.Ckfinite, new CkfiniteStackMutator()},
213+
{OpCodes.Localloc, new LocallocStackMutator()},
213214
};
214215

215216
private static readonly MarkLabelStackMutator markLabelStackMutator = new MarkLabelStackMutator();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
using System;
2+
3+
namespace GrEmit.StackMutators
4+
{
5+
internal class LocallocStackMutator : StackMutator
6+
{
7+
public override void Mutate(GroboIL il, ILInstructionParameter parameter, ref EvaluationStack stack)
8+
{
9+
CheckNotEmpty(il, stack, () => $"In order to perform the instruction 'localloc' size must be loaded onto the evaluation stack");
10+
var type = stack.Pop();
11+
if (ToCLIType(type) != CLIType.NativeInt)
12+
ThrowError(il, $"Unable to perform the instruction 'localloc' on type '{type}'");
13+
stack.Push(typeof(UIntPtr));
14+
}
15+
}
16+
}

0 commit comments

Comments
 (0)