Skip to content

Commit

Permalink
Avoid optimizing away ref array access
Browse files Browse the repository at this point in the history
  • Loading branch information
jjonescz committed Jul 25, 2024
1 parent ed5fa5e commit 7cf05b4
Show file tree
Hide file tree
Showing 7 changed files with 411 additions and 9 deletions.
7 changes: 7 additions & 0 deletions src/Compilers/CSharp/Portable/BoundTree/BoundNodes.xml
Original file line number Diff line number Diff line change
Expand Up @@ -659,6 +659,13 @@

<Field Name="Expression" Type="BoundExpression"/>
<Field Name="Indices" Type="ImmutableArray&lt;BoundExpression&gt;"/>

<!--
Ref array access has side effects (element type mismatch check)
so if it remains standalone (e.g., because the result is discarded)
we need to know if the original assignment was ref to emit it correctly.
-->
<Field Name="IsRef" Type="bool" />
</Node>

<!--
Expand Down
19 changes: 19 additions & 0 deletions src/Compilers/CSharp/Portable/BoundTree/Constructors.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,25 @@

namespace Microsoft.CodeAnalysis.CSharp
{
internal sealed partial class BoundArrayAccess
{
public BoundArrayAccess(
SyntaxNode syntax,
BoundExpression expression,
ImmutableArray<BoundExpression> indices,
TypeSymbol type,
bool hasErrors = false)
: this(syntax, expression, indices, isRef: false, type, hasErrors)
{
}

public BoundArrayAccess Update(BoundExpression expression, ImmutableArray<BoundExpression> indices, TypeSymbol type)
=> this.Update(expression, indices, isRef: this.IsRef, type);

public BoundArrayAccess Update(bool isRef)
=> this.Update(Expression, Indices, isRef: isRef, Type);
}

internal sealed partial class BoundFieldAccess
{
public BoundFieldAccess(
Expand Down
7 changes: 7 additions & 0 deletions src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1003,6 +1003,13 @@ internal static RefKind GetArgumentRefKind(ImmutableArray<BoundExpression> argum

private void EmitArrayElementLoad(BoundArrayAccess arrayAccess, bool used)
{
if (arrayAccess.IsRef)
{
EmitArrayElementAddress(arrayAccess, AddressKind.Writeable);
EmitPopIfUnused(used);
return;
}

EmitExpression(arrayAccess.Expression, used: true);
EmitArrayIndices(arrayAccess.Indices);

Expand Down
5 changes: 5 additions & 0 deletions src/Compilers/CSharp/Portable/CodeGen/Optimizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2186,6 +2186,11 @@ public override BoundNode VisitAssignmentOperator(BoundAssignmentOperator node)

if (isLast)
{
if (node.IsRef && right is BoundArrayAccess arrayAccess)
{
return arrayAccess.Update(isRef: true);
}

// assigned local is not used later => just emit the Right
return right;
}
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,11 @@ private BoundExpression MakeStaticAssignmentOperator(

case BoundKind.DiscardExpression:
{
if (isRef && rewrittenRight is BoundArrayAccess arrayAccess)
{
return arrayAccess.Update(isRef: true);
}

return rewrittenRight;
}

Expand Down
Loading

0 comments on commit 7cf05b4

Please sign in to comment.