Skip to content

Commit

Permalink
(#100) CodeGen: for loop statement
Browse files Browse the repository at this point in the history
  • Loading branch information
Griboedoff committed May 2, 2022
1 parent 0dde33d commit 4839230
Show file tree
Hide file tree
Showing 8 changed files with 196 additions and 0 deletions.
53 changes: 53 additions & 0 deletions Cesium.CodeGen.Tests/CodeGenForTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
namespace Cesium.CodeGen.Tests;

public class CodeGenForTests : CodeGenTestBase
{
private static Task DoTest(string source)
{
var assembly = GenerateAssembly(default, source);

var moduleType = assembly.Modules.Single().GetType("<Module>");
return VerifyMethods(moduleType);
}

[Fact]
public Task SimpleFor() => DoTest(
@"int main()
{
int i;
for(i = 0; i < 10; ++i) ++i;
}");

[Fact]
public Task ForTest_NoInit() => DoTest(
@"int main()
{
int i = 0;
for(; i < 10; ++i) ++i;
}");


[Fact]
public Task For_NoTest() => DoTest(
@"int main()
{
int i;
for(i = 0; ; ++i) ++i;
}");

[Fact]
public Task For_NoUpdate() => DoTest(
@"int main()
{
int i;
for(i = 0; i < 10; ) ++i;
}");

[Fact]
public Task For_Empty() => DoTest(
@"int main()
{
int i;
for(;;) ++i;
}");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
System.Int32 <Module>::main()
Locals:
System.Int32 V_0
IL_0000: ldc.i4 0
IL_0005: stloc V_0
IL_0009: br IL_002a
IL_000e: ldloc V_0
IL_0012: ldc.i4 1
IL_0017: add
IL_0018: stloc V_0
IL_001c: ldloc V_0
IL_0020: ldc.i4 1
IL_0025: add
IL_0026: stloc V_0
IL_002a: ldloc V_0
IL_002e: ldc.i4 10
IL_0033: clt
IL_0035: brtrue IL_000e
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
System.Int32 <Module>::main()
Locals:
System.Int32 V_0
IL_0000: br IL_0013
IL_0005: ldloc V_0
IL_0009: ldc.i4 1
IL_000e: add
IL_000f: stloc V_0
IL_0013: ldc.i4 1
IL_0018: brtrue IL_0005
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
System.Int32 <Module>::main()
Locals:
System.Int32 V_0
IL_0000: ldc.i4 0
IL_0005: stloc V_0
IL_0009: br IL_002a
IL_000e: ldloc V_0
IL_0012: ldc.i4 1
IL_0017: add
IL_0018: stloc V_0
IL_001c: ldloc V_0
IL_0020: ldc.i4 1
IL_0025: add
IL_0026: stloc V_0
IL_002a: ldc.i4 1
IL_002f: brtrue IL_000e
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
System.Int32 <Module>::main()
Locals:
System.Int32 V_0
IL_0000: ldc.i4 0
IL_0005: stloc V_0
IL_0009: br IL_001c
IL_000e: ldloc V_0
IL_0012: ldc.i4 1
IL_0017: add
IL_0018: stloc V_0
IL_001c: ldloc V_0
IL_0020: ldc.i4 10
IL_0025: clt
IL_0027: brtrue IL_000e
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
System.Int32 <Module>::main()
Locals:
System.Int32 V_0
IL_0000: ldc.i4 0
IL_0005: stloc V_0
IL_0009: br IL_002a
IL_000e: ldloc V_0
IL_0012: ldc.i4 1
IL_0017: add
IL_0018: stloc V_0
IL_001c: ldloc V_0
IL_0020: ldc.i4 1
IL_0025: add
IL_0026: stloc V_0
IL_002a: ldloc V_0
IL_002e: ldc.i4 10
IL_0033: clt
IL_0035: brtrue IL_000e
1 change: 1 addition & 0 deletions Cesium.CodeGen/Extensions/BlockItemEx.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ internal static class BlockItemEx
Ast.ReturnStatement s => new ReturnStatement(s),
Ast.ExpressionStatement s => new ExpressionStatement(s),
Ast.IfElseStatement s => new IfElseStatement(s),
Ast.ForStatement s => new ForStatement(s),
_ => throw new NotImplementedException($"Statement not supported, yet: {blockItem}.")
};
}
66 changes: 66 additions & 0 deletions Cesium.CodeGen/Ir/BlockItems/ForStatement.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using Cesium.CodeGen.Contexts;
using Cesium.CodeGen.Extensions;
using Cesium.CodeGen.Ir.Expressions;
using Cesium.CodeGen.Ir.Expressions.Constants;
using Mono.Cecil.Cil;
using ConstantExpression = Cesium.CodeGen.Ir.Expressions.ConstantExpression;

namespace Cesium.CodeGen.Ir.BlockItems;

internal class ForStatement : IBlockItem
{
private readonly IExpression? _initExpression;
private readonly IExpression _testExpression;
private readonly IExpression? _updateExpression;
private readonly IBlockItem _body;

public ForStatement(Ast.ForStatement statement)
{
var (initExpression, testExpression, updateExpression, body) = statement;
_initExpression = initExpression?.ToIntermediate();
// 6.8.5.3.2 if testExpression is null it should be replaced by nonzero constant
_testExpression = testExpression?.ToIntermediate() ?? new ConstantExpression(new IntegerConstant("1"));
_updateExpression = updateExpression?.ToIntermediate();
_body = body.ToIntermediate();
}

private ForStatement(
IExpression? initExpression,
IExpression testExpression,
IExpression? updateExpression,
IBlockItem body)
{
_initExpression = initExpression;
_testExpression = testExpression;
_updateExpression = updateExpression;
_body = body;
}

public IBlockItem Lower()
=> new ForStatement(
_initExpression?.Lower(),
_testExpression.Lower(),
_updateExpression?.Lower(),
_body.Lower());

public void EmitTo(FunctionScope scope)
{
var bodyProcessor = scope.Method.Body.GetILProcessor();
var instructions = bodyProcessor.Body.Instructions;
var stub = bodyProcessor.Create(OpCodes.Nop);

_initExpression?.EmitTo(scope);
var brToTest = bodyProcessor.Create(OpCodes.Br, stub);
bodyProcessor.Append(brToTest);
var loopStartIndex = instructions.Count;
_body.EmitTo(scope);
_updateExpression?.EmitTo(scope);
var testStartIndex = instructions.Count;
_testExpression.EmitTo(scope);
var testStart = instructions[testStartIndex];
brToTest.Operand = testStart;

var loopStart = instructions[loopStartIndex];
bodyProcessor.Emit(OpCodes.Brtrue, loopStart);
}
}

0 comments on commit 4839230

Please sign in to comment.