Skip to content

Commit

Permalink
adds support for loading local Inline Arrary element at index 0 (#257)
Browse files Browse the repository at this point in the history
  • Loading branch information
adrianoc committed Mar 27, 2024
1 parent acc55ab commit 1eb8e43
Show file tree
Hide file tree
Showing 4 changed files with 46 additions and 11 deletions.
27 changes: 25 additions & 2 deletions Cecilifier.Core.Tests/Tests/Unit/InlineArrayTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public struct IntBuffer
}

[Test]
public void AccessToFirstElement_MapsTo_PrivateImplementationDetailsInlineArrayFirstElementRefMethod()
public void AssignmentToFirstElement_MapsTo_PrivateImplementationDetailsInlineArrayFirstElementRefMethod()
{
var result = RunCecilifier("""
var buffer = new IntBuffer();
Expand Down Expand Up @@ -84,6 +84,29 @@ public struct IntBuffer
"""));
}

[Test]
public void AccessToFirstElement_MapsTo_PrivateImplementationDetailsInlineArrayFirstElementRefMethod()
{
var result = RunCecilifier("""
var buffer = new IntBuffer();
buffer[0] = 42;
System.Console.WriteLine(buffer[0]);
[System.Runtime.CompilerServices.InlineArray(10)]
public struct IntBuffer
{
private int _element0;
}
""");

var cecilified = result.GeneratedCode.ReadToEnd();

Assert.That(cecilified, Does.Match("""
(il_topLevelMain_\d+\.Emit\(OpCodes\.)Call, gi_inlineArrayFirstElementRef_\d+\);
\s+\1Ldind_I4\);
\s+\1Call,.+ImportReference\(.+ResolveMethod\(typeof\(System.Console\), "WriteLine".+\);
"""));
}

// Access to not first element
//
}
5 changes: 2 additions & 3 deletions Cecilifier.Core/AST/AssignmentVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,10 @@ internal AssignmentVisitor(IVisitorContext ctx, string ilVar) : base(ctx)
public override void VisitElementAccessExpression(ElementAccessExpressionSyntax node)
{
var lastInstructionLoadingRhs = Context.CurrentLine;
if (InlineArrayProcessor.HandleInlineArrayElementAccess(Context, ilVar, node))
if (InlineArrayProcessor.TryHandleInlineArrayElementAccess(Context, ilVar, node, out var elementType))
{
Context.MoveLinesToEnd(InstructionPrecedingValueToLoad, lastInstructionLoadingRhs);
var arrayElementType = Context.SemanticModel.GetTypeInfo(node).Type.EnsureNotNull();
Context.EmitCilInstruction(ilVar, arrayElementType.Stind());
Context.EmitCilInstruction(ilVar, elementType.StindOpCodeFor());
return;
}

Expand Down
6 changes: 6 additions & 0 deletions Cecilifier.Core/AST/ExpressionVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,12 @@ public override void VisitElementAccessExpression(ElementAccessExpressionSyntax
return;
}

if (InlineArrayProcessor.TryHandleInlineArrayElementAccess(Context, ilVar, node, out var elementType))
{
Context.EmitCilInstruction(ilVar, elementType.LdindOpCodeFor());
return;
}

node.Expression.Accept(this);
node.ArgumentList.Accept(this);

Expand Down
19 changes: 13 additions & 6 deletions Cecilifier.Core/AST/InlineArrayProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -77,29 +77,31 @@ static string InlineArrayAsSpanMethodFor(IVisitorContext context, ITypeSymbol in
}
}

internal static bool HandleInlineArrayElementAccess(IVisitorContext context, string ilVar, ElementAccessExpressionSyntax elementAccess)
internal static bool TryHandleInlineArrayElementAccess(IVisitorContext context, string ilVar, ElementAccessExpressionSyntax elementAccess, out ITypeSymbol elementType)
{
elementType = null;
if (elementAccess.Expression.IsKind(SyntaxKind.ElementAccessExpression))
return false;

var expSymbol = context.SemanticModel.GetSymbolInfo(elementAccess.Expression).Symbol.EnsureNotNull();
if (expSymbol.GetMemberType().TryGetAttribute<InlineArrayAttribute>(out _))
var inlineArrayType = context.SemanticModel.GetSymbolInfo(elementAccess.Expression).Symbol.EnsureNotNull().GetMemberType();
if (inlineArrayType.TryGetAttribute<InlineArrayAttribute>(out _))
{
ExpressionVisitor.Visit(context, ilVar, elementAccess.Expression);
Debug.Assert(elementAccess.ArgumentList.Arguments.Count == 1);

var method = string.Empty;
if (elementAccess.ArgumentList.Arguments[0].Expression.TryGetLiteralValueFor(out int index) && index == 0)
{
method = InlineArrayFirstElementRefMethodFor(context, expSymbol.GetMemberType());
method = InlineArrayFirstElementRefMethodFor(context, inlineArrayType);
}
else
{
context.EmitCilInstruction(ilVar, OpCodes.Ldc_I4, index);
method = InlineArrayElementRefMethodFor(context, expSymbol.GetMemberType());
method = InlineArrayElementRefMethodFor(context, inlineArrayType);
}
context.EmitCilInstruction(ilVar, OpCodes.Call, method);

elementType = InlineArrayElementTypeFrom(inlineArrayType);
return true;
}

Expand Down Expand Up @@ -132,7 +134,7 @@ private static string PrivateImplementationInlineArrayGenericInstanceMethodFor(I
varName,
[
context.TypeResolver.Resolve(inlineArrayType), // TBuffer
context.TypeResolver.Resolve(((IFieldSymbol) inlineArrayType.GetMembers().First()).Type) // TElement
context.TypeResolver.Resolve(InlineArrayElementTypeFrom(inlineArrayType)) // TElement
]);

foreach (var exp in exps)
Expand All @@ -143,6 +145,11 @@ private static string PrivateImplementationInlineArrayGenericInstanceMethodFor(I

return varName;
}

private static ITypeSymbol InlineArrayElementTypeFrom(ITypeSymbol inlineArrayType)
{
return ((IFieldSymbol) inlineArrayType.GetMembers().First()).Type;
}

private static int InlineArrayLengthFrom(ITypeSymbol rhsType)
{
Expand Down

0 comments on commit 1eb8e43

Please sign in to comment.