Skip to content

Commit

Permalink
(#332) CodeGen: reduce mutations in StructType
Browse files Browse the repository at this point in the history
  • Loading branch information
ForNeVeR committed Mar 3, 2024
1 parent b4c17c2 commit e43cdfc
Show file tree
Hide file tree
Showing 8 changed files with 119 additions and 23 deletions.
11 changes: 11 additions & 0 deletions Cesium.CodeGen.Tests/CodeGenTypeTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -410,4 +410,15 @@ int main() {
return f.a + f.b + f.inner._1 + f.inner._2 + f.other_inner.ha + f.other_inner.he + f.level_1.level_2.level_3 + f.named_union.not_anon + f.anon_int + f.integer;
}
");

[Fact]
public Task LocalStructTest() => DoTest("""
int main(void) {
struct foo {
int x;
} bar;
bar.x = 42;
return bar.x;
}
""");
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
Module: Primary
Type: <Module>
Methods:
System.Int32 <Module>::main()
Locals:
foo V_0
IL_0000: ldloca.s V_0
IL_0002: ldc.i4.s 42
IL_0004: stfld System.Int32 foo::x
IL_0009: ldloca.s V_0
IL_000b: ldfld System.Int32 foo::x
IL_0010: ret

System.Int32 <Module>::<SyntheticEntrypoint>()
Locals:
System.Int32 V_0
IL_0000: call System.Int32 <Module>::main()
IL_0005: stloc.s V_0
IL_0007: ldloc.s V_0
IL_0009: call System.Void Cesium.Runtime.RuntimeHelpers::Exit(System.Int32)
IL_000e: ldloc.s V_0
IL_0010: ret

Type: foo
Fields:
System.Int32 foo::x
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@
IL_0027: ldflda _Union_Long__5u_Int__6u <typedef>foo::uni
IL_002c: ldc.i4.s 10
IL_002e: conv.i8
IL_002f: stfld System.Int64 _Union_Long__5u_Int__6u::_5u
IL_002f: stfld System.Int64 <typedef>_Union_Long__5u_Int__6u::_5u
IL_0034: ldloca.s V_0
IL_0036: ldflda _Anon_Int__7 <typedef>foo::s
IL_003b: ldc.i4.s 10
IL_003d: stfld System.Int32 _Anon_Int__7::_7
IL_003d: stfld System.Int32 <typedef>_Anon_Int__7::_7
IL_0042: ldloca.s V_0
IL_0044: ldfld System.Int32 <typedef>foo::_1
IL_0049: ldloca.s V_0
Expand All @@ -37,11 +37,11 @@
IL_0062: add
IL_0063: ldloca.s V_0
IL_0065: ldflda _Union_Long__5u_Int__6u <typedef>foo::uni
IL_006a: ldfld System.Int32 _Union_Long__5u_Int__6u::_6u
IL_006a: ldfld System.Int32 <typedef>_Union_Long__5u_Int__6u::_6u
IL_006f: add
IL_0070: ldloca.s V_0
IL_0072: ldflda _Anon_Int__7 <typedef>foo::s
IL_0077: ldfld System.Int32 _Anon_Int__7::_7
IL_0077: ldfld System.Int32 <typedef>_Anon_Int__7::_7
IL_007c: add
IL_007d: ret

Expand Down Expand Up @@ -80,3 +80,12 @@
Type: _Anon_Int__7
Fields:
System.Int32 _Anon_Int__7::_7

Type: <typedef>_Union_Long__5u_Int__6u
Fields:
System.Int64 <typedef>_Union_Long__5u_Int__6u::_5u
System.Int32 <typedef>_Union_Long__5u_Int__6u::_6u

Type: <typedef>_Anon_Int__7
Fields:
System.Int32 <typedef>_Anon_Int__7::_7
Original file line number Diff line number Diff line change
Expand Up @@ -64,29 +64,29 @@
IL_00cb: conv.i8
IL_00cc: ldloca.s V_0
IL_00ce: ldflda _Anon_Long__1_Long__2 Foo::inner
IL_00d3: ldfld System.Int64 _Anon_Long__1_Long__2::_1
IL_00d3: ldfld System.Int64 <typedef>_Anon_Long__1_Long__2::_1
IL_00d8: add
IL_00d9: ldloca.s V_0
IL_00db: ldflda _Anon_Long__1_Long__2 Foo::inner
IL_00e0: ldfld System.Int64 _Anon_Long__1_Long__2::_2
IL_00e0: ldfld System.Int64 <typedef>_Anon_Long__1_Long__2::_2
IL_00e5: add
IL_00e6: ldloca.s V_0
IL_00e8: ldflda _Anon_Long_he_Long_ha Foo::other_inner
IL_00ed: ldfld System.Int64 _Anon_Long_he_Long_ha::ha
IL_00ed: ldfld System.Int64 <typedef>_Anon_Long_he_Long_ha::ha
IL_00f2: add
IL_00f3: ldloca.s V_0
IL_00f5: ldflda _Anon_Long_he_Long_ha Foo::other_inner
IL_00fa: ldfld System.Int64 _Anon_Long_he_Long_ha::he
IL_00fa: ldfld System.Int64 <typedef>_Anon_Long_he_Long_ha::he
IL_00ff: add
IL_0100: ldloca.s V_0
IL_0102: ldflda _Anon__level_2 Foo::level_1
IL_0107: ldflda _Anon_Int_level_3 _Anon__level_2::level_2
IL_010c: ldfld System.Int32 _Anon_Int_level_3::level_3
IL_0107: ldflda <typedef>_Anon_Int_level_3 <typedef>_Anon__level_2::level_2
IL_010c: ldfld System.Int32 <typedef>_Anon_Int_level_3::level_3
IL_0111: conv.i8
IL_0112: add
IL_0113: ldloca.s V_0
IL_0115: ldflda _Union_Int_not_anon_Float_its Foo::named_union
IL_011a: ldfld System.Int32 _Union_Int_not_anon_Float_its::not_anon
IL_011a: ldfld System.Int32 <typedef>_Union_Int_not_anon_Float_its::not_anon
IL_011f: conv.i8
IL_0120: add
IL_0121: ldloca.s V_0
Expand Down Expand Up @@ -153,3 +153,26 @@
Type: _Anon__level_2
Fields:
_Anon_Int_level_3 _Anon__level_2::level_2

Type: <typedef>_Anon_Long__1_Long__2
Fields:
System.Int64 <typedef>_Anon_Long__1_Long__2::_1
System.Int64 <typedef>_Anon_Long__1_Long__2::_2

Type: <typedef>_Anon_Long_he_Long_ha
Fields:
System.Int64 <typedef>_Anon_Long_he_Long_ha::he
System.Int64 <typedef>_Anon_Long_he_Long_ha::ha

Type: <typedef>_Anon_Int_level_3
Fields:
System.Int32 <typedef>_Anon_Int_level_3::level_3

Type: <typedef>_Anon__level_2
Fields:
<typedef>_Anon_Int_level_3 <typedef>_Anon__level_2::level_2

Type: <typedef>_Union_Int_not_anon_Float_its
Fields:
System.Int32 <typedef>_Union_Int_not_anon_Float_its::not_anon
System.Single <typedef>_Union_Int_not_anon_Float_its::its
10 changes: 9 additions & 1 deletion Cesium.CodeGen/Ir/Expressions/SizeOfOperatorExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,15 @@ public SizeOfOperatorExpression(IType Type)

public void EmitTo(IEmitScope scope)
{
var type = _type.Resolve(scope.Context);
var context = scope.Context;

// As sizeof is a type operator, it may need to emit anonymous types right here.
if (_type is IGeneratedType generatedType && !generatedType.IsAlreadyEmitted(context))
{
generatedType.EmitType(context);
}

var type = _type.Resolve(context);
scope.SizeOf(type);
}

Expand Down
6 changes: 6 additions & 0 deletions Cesium.CodeGen/Ir/Expressions/Values/LValueInstanceField.cs
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,12 @@ protected override FieldReference GetField(IEmitScope scope)

List<FieldDefinition>? path = null;

if (!_structType.IsAlreadyEmitted(scope.Context))
{
// The last-chance try to emit the type:
_structType.EmitType(scope.Context);
}

var valueTypeReference = _structType.Resolve(scope.Context);
var valueTypeDef = valueTypeReference.Resolve();

Expand Down
6 changes: 5 additions & 1 deletion Cesium.CodeGen/Ir/Types/IType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,11 @@ IExpression GetSizeInBytesExpression(TargetArchitectureSet arch)
/// <summary>A generated type, i.e. a type that has some bytecode to be generated once.</summary>
internal interface IGeneratedType : IType
{
public string? Identifier { get; }
TypeDefinition StartEmit(string name, TranslationUnitContext context);
void FinishEmit(TypeDefinition definition, string name, TranslationUnitContext context);

public bool IsAlreadyEmitted(TranslationUnitContext context);

/// <summary>Fully emits the type.</summary>
void EmitType(TranslationUnitContext context);
}
29 changes: 19 additions & 10 deletions Cesium.CodeGen/Ir/Types/StructType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,13 @@
using Cesium.CodeGen.Ir.Expressions;
using Cesium.Core;
using Mono.Cecil;
using Mono.Cecil.Cil;

namespace Cesium.CodeGen.Ir.Types;

internal sealed class StructType : IGeneratedType, IEquatable<StructType>
{
internal const string AnonStructPrefix = "_Anon_";
internal const string AnonUnionPrefix = "_Union_";
private const string AnonStructPrefix = "_Anon_";
private const string AnonUnionPrefix = "_Union_";

private TypeReference? AnonType;

Expand All @@ -21,7 +20,7 @@ public StructType(IReadOnlyList<LocalDeclarationInfo> members, bool isUnion, str
IsUnion = isUnion;
Identifier = identifier;
IsAnon = identifier == null;
if (IsAnon) AnonIndentifier = CreateAnonIdentifier(members, isUnion);
if (IsAnon) AnonIdentifier = CreateAnonIdentifier(members, isUnion);
}

public bool IsAnon { get; private set; }
Expand All @@ -35,7 +34,7 @@ public StructType(IReadOnlyList<LocalDeclarationInfo> members, bool isUnion, str
public string? Identifier { get; }

// We need a good name generator...
internal string? AnonIndentifier { get; }
private string? AnonIdentifier;

public TypeDefinition StartEmit(string name, TranslationUnitContext context)
{
Expand Down Expand Up @@ -74,7 +73,7 @@ public void FinishEmit(TypeDefinition definition, string name, TranslationUnitCo
{
if (type is StructType structType && structType.IsAnon)
{
identifier = structType.AnonIndentifier;
identifier = structType.AnonIdentifier;
}
else
throw new NotImplementedException($"Unexpected field with null ident and with type: {type}");
Expand All @@ -93,9 +92,20 @@ public void FinishEmit(TypeDefinition definition, string name, TranslationUnitCo
}
}

public void EmitType(TranslationUnitContext context)
{
var name = Identifier ?? CreateAnonIdentifier(Members, IsUnion);
context.GenerateType(name, this);
}

public bool IsAlreadyEmitted(TranslationUnitContext context) => context.GetTypeReference(this) != null;

private void EmitAsAnonStructure(TranslationUnitContext context)
{
var type = new TypeDefinition(string.Empty, IsAnon ? AnonIndentifier : Identifier, TypeAttributes.Public | TypeAttributes.Sealed,
var type = new TypeDefinition(
string.Empty,
CreateAnonIdentifier(Members, IsUnion),
TypeAttributes.Public | TypeAttributes.Sealed,
context.Module.ImportReference(context.AssemblyContext.MscorlibAssembly.GetType("System.ValueType")));

FinishEmit(type, type.Name, context); // emit fields
Expand All @@ -117,15 +127,14 @@ public TypeReference Resolve(TranslationUnitContext context)

if (resolved == null)
{
if (IsAnon || Members.Count != 0)
if (IsAnon)
{
if (AnonType == null)
EmitAsAnonStructure(context);

return AnonType!; // not null
}

throw new CompilationException($"Can't find the type with name: {Identifier}");
throw new CompilationException($"Type {this} was not found.");
}

return resolved;
Expand Down

0 comments on commit e43cdfc

Please sign in to comment.