Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve code generation for functions #637

Merged
merged 1 commit into from
Sep 5, 2024
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
17 changes: 13 additions & 4 deletions Cesium.CodeGen.Tests/CodeGenMethodTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -342,14 +342,23 @@ public Task ImplicitReturnAllowedForMain() => DoTest(@"int main()
int unused = 0;
}");

[Fact, NoVerify]
public void ImplicitReturnDisallowedNonMain() => DoesNotCompile(@"int foo()
[Fact]
public void ImplicitReturnAllowedNonMain() => DoTest(@"int foo()
{
int unused;
}", "Function foo has no return statement.");
}");

[Fact, NoVerify]
public void ExpressionReturnDisallowedInVoidFunction() => DoesNotCompile(@"void foo()
{
return 4;
}", "Function foo has return type void, and thus cannot have expression in return.");

[Fact]
public Task ReturnInsideInfiniteForTest() => DoTest("void test() { for(;;) { return; } }");

[Fact]
public Task ReturnInsideInfiniteForTest() => DoTest("int test() { for(;;) { return; } }");
public Task ReturnValueInsideInfiniteForTest() => DoTest("int test() { for(;;) { return 5; } }");

[Fact]
public Task ConsumeUnusedResult() => DoTest(@"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
IL_0014: ldc.i4.0
IL_0015: ret
IL_0016: nop
IL_0017: ldc.i4.0
IL_0018: ret

System.Int32 <Module>::<SyntheticEntrypoint>()
Locals:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@
IL_0012: ldc.i4.0
IL_0013: ret
IL_0014: nop
IL_0015: ldc.i4.0
IL_0016: ret

System.Int32 <Module>::<SyntheticEntrypoint>()
Locals:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
System.Int32 <Module>::foo()
IL_0000: ldc.i4.0
IL_0001: ret
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
System.Int32 <Module>::test()
System.Void <Module>::test()
IL_0000: nop
IL_0001: ret
IL_0002: nop
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
System.Int32 <Module>::test()
IL_0000: nop
IL_0001: ldc.i4.5
IL_0002: ret
IL_0003: nop
IL_0004: br IL_0000
IL_0009: nop
IL_000a: ldc.i4.0
IL_000b: ret
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
IL_002b: nop
IL_002c: br IL_0006
IL_0031: nop
IL_0032: ldc.i4.0
IL_0033: ret

System.Int32 <Module>::<SyntheticEntrypoint>()
Locals:
Expand Down
6 changes: 6 additions & 0 deletions Cesium.CodeGen/Ir/BlockItems/FunctionDefinition.cs
Original file line number Diff line number Diff line change
Expand Up @@ -280,5 +280,11 @@ private void EmitCode(FunctionScope scope)
);

BlockItemEmitting.EmitCode(scope, transformed);
var isVoid = scope.FunctionInfo.ReturnType.Equals(CTypeSystem.Void);
if (!isVoid && scope.Method.Body.Instructions.Last().OpCode != OpCodes.Ret)
{
scope.Method.Body.Instructions.Add(Instruction.Create(OpCodes.Ldc_I4_0));
scope.Method.Body.Instructions.Add(Instruction.Create(OpCodes.Ret));
}
}
}
17 changes: 10 additions & 7 deletions Cesium.CodeGen/Ir/ControlFlow/ControlFlowChecker.cs
Original file line number Diff line number Diff line change
Expand Up @@ -314,19 +314,22 @@ bool isMain
var isVoidFn = returnType.Equals(CTypeSystem.Void);
var isReturnRequired = !isVoidFn && !isMain;

if (isVoidFn)
{
var hasExpressionReturn = (ReturnStatement?)dset.Vertices.FirstOrDefault(_ => _.BlockItem is ReturnStatement { Expression: { } })?.BlockItem;
if (hasExpressionReturn is not null)
{
throw new CompilationException($"Function {scope.Method.Name} has return type void, and thus cannot have expression in return.");
}
}

foreach (var preTerminator in preTerminators)
{
if (preTerminator.BlockItem is ReturnStatement) continue;
if (preTerminator.Reached == false) continue;

if (isReturnRequired)
{
// bad error message
throw new CompilationException($"Function {scope.Method.Name} has no return statement.");
}

// inserting fake return
var retn = new ReturnStatement(isMain ? new ConstantLiteralExpression(new IntegerConstant(0)) : null);
var retn = new ReturnStatement(!isVoidFn ? new ConstantLiteralExpression(new IntegerConstant(0)) : null);

if (preTerminator.BlockItem is {} original)
{
Expand Down
5 changes: 5 additions & 0 deletions Cesium.IntegrationTests/functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ void forward_declaration_void_2()
// Do nothing here.
}

int missing_return()
{
// Do nothing here.
}

int main(void)
{
return foo();
Expand Down
17 changes: 17 additions & 0 deletions Cesium.IntegrationTests/if.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#include <stdio.h>

int test()
{
int a = 0;
if (1)
return 3;
else
a = 2;
}

int main(int argc, char *argv[])
{
if (test() != 3) return -1;

return 42;
}
Loading