Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 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
Original file line number Diff line number Diff line change
Expand Up @@ -831,12 +831,19 @@ private BoundExpression CreateAndPopulateArray(BoundCollectionExpression node, A

RewriteCollectionExpressionElementsIntoTemporaries(elements, numberIncludingLastSpread, localsBuilder, sideEffects);

// int index = 0;
BoundLocal indexTemp = _factory.StoreToTemp(
_factory.Literal(0),
out assignmentToTemp);
localsBuilder.Add(indexTemp);
sideEffects.Add(assignmentToTemp);
// indexTemp is null when we can use constant compile-time indices.
// indexTemp is non-null when we need a runtime-tracked index variable (for spread elements).
BoundLocal? indexTemp = null;

if (numberIncludingLastSpread != 0)
{
// int index = 0;
indexTemp = _factory.StoreToTemp(
_factory.Literal(0),
out assignmentToTemp);
localsBuilder.Add(indexTemp);
sideEffects.Add(assignmentToTemp);
}

// ElementType[] array = new ElementType[N + s1.Length + ...];
BoundLocal arrayTemp = _factory.StoreToTemp(
Expand All @@ -848,6 +855,7 @@ private BoundExpression CreateAndPopulateArray(BoundCollectionExpression node, A
localsBuilder.Add(arrayTemp);
sideEffects.Add(assignmentToTemp);

int currentElementIndex = 0;
AddCollectionExpressionElements(
elements,
arrayTemp,
Expand All @@ -857,33 +865,49 @@ private BoundExpression CreateAndPopulateArray(BoundCollectionExpression node, A
addElement: (ArrayBuilder<BoundExpression> expressions, BoundExpression arrayTemp, BoundExpression rewrittenValue, bool isLastElement) =>
{
Debug.Assert(arrayTemp.Type is ArrayTypeSymbol);
Debug.Assert(indexTemp.Type is { SpecialType: SpecialType.System_Int32 });

var expressionSyntax = rewrittenValue.Syntax;
var elementType = ((ArrayTypeSymbol)arrayTemp.Type).ElementType;

// array[index] = element;
expressions.Add(
new BoundAssignmentOperator(
expressionSyntax,
_factory.ArrayAccess(arrayTemp, indexTemp),
rewrittenValue,
isRef: false,
elementType));
if (!isLastElement)
if (indexTemp is null)
{
// index = index + 1;
// array[0] = element; array[1] = element; etc.
expressions.Add(
new BoundAssignmentOperator(
expressionSyntax,
indexTemp,
_factory.Binary(BinaryOperatorKind.Addition, indexTemp.Type, indexTemp, _factory.Literal(1)),
_factory.ArrayAccess(arrayTemp, _factory.Literal(currentElementIndex)),
rewrittenValue,
isRef: false,
indexTemp.Type));
elementType));
currentElementIndex++;
}
else
{
// array[index] = element;
expressions.Add(
new BoundAssignmentOperator(
expressionSyntax,
_factory.ArrayAccess(arrayTemp, indexTemp),
rewrittenValue,
isRef: false,
elementType));
if (!isLastElement)
{
// index = index + 1;
expressions.Add(
new BoundAssignmentOperator(
expressionSyntax,
indexTemp,
_factory.Binary(BinaryOperatorKind.Addition, indexTemp.Type, indexTemp, _factory.Literal(1)),
isRef: false,
indexTemp.Type));
}
}
},
tryOptimizeSpreadElement: (ArrayBuilder<BoundExpression> sideEffects, BoundExpression arrayTemp, BoundCollectionExpressionSpreadElement spreadElement, BoundExpression rewrittenSpreadOperand) =>
{
Debug.Assert(indexTemp is not null);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot add a comment mentioning that if we have spreads we expect o always need an index currently.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added comments in commit 38fdece to clarify that when spreads are present, we always need a runtime-tracked index variable.


if (PrepareCopyToOptimization(spreadElement, rewrittenSpreadOperand) is not var (spanSliceMethod, spreadElementAsSpan, getLengthMethod, copyToMethod))
return false;

Expand Down Expand Up @@ -1177,13 +1201,21 @@ private BoundExpression CreateAndPopulateList(BoundCollectionExpression node, Ty
// Populate the span.
var spanGetItem = ((MethodSymbol)_factory.WellKnownMember(WellKnownMember.System_Span_T__get_Item)).AsMember((NamedTypeSymbol)spanTemp.Type);

// int index = 0;
BoundLocal indexTemp = _factory.StoreToTemp(
_factory.Literal(0),
out assignmentToTemp);
localsBuilder.Add(indexTemp);
sideEffects.Add(assignmentToTemp);
// indexTemp is null when we can use constant compile-time indices.
// indexTemp is non-null when we need a runtime-tracked index variable (for spread elements).
BoundLocal? indexTemp = null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

review with whitespace off.


if (numberIncludingLastSpread != 0)
{
// int index = 0;
indexTemp = _factory.StoreToTemp(
_factory.Literal(0),
out assignmentToTemp);
localsBuilder.Add(indexTemp);
sideEffects.Add(assignmentToTemp);
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot CreateAndPopulateArray contains very similar logic for arrays. can you update the PR to use constant indices for those as well when possible?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Applied constant indices optimization to arrays in commit 9ffa846. Arrays now use the same optimization as Lists when there are no spread elements.


int currentElementIndex = 0;
AddCollectionExpressionElements(
elements,
spanTemp,
Expand All @@ -1193,33 +1225,49 @@ private BoundExpression CreateAndPopulateList(BoundCollectionExpression node, Ty
addElement: (ArrayBuilder<BoundExpression> expressions, BoundExpression spanTemp, BoundExpression rewrittenValue, bool isLastElement) =>
{
Debug.Assert(spanTemp.Type is NamedTypeSymbol);
Debug.Assert(indexTemp.Type is { SpecialType: SpecialType.System_Int32 });

var expressionSyntax = rewrittenValue.Syntax;
var elementType = ((NamedTypeSymbol)spanTemp.Type).TypeArgumentsWithAnnotationsNoUseSiteDiagnostics[0].Type;

// span[index] = element;
expressions.Add(
new BoundAssignmentOperator(
expressionSyntax,
_factory.Call(spanTemp, spanGetItem, indexTemp),
rewrittenValue,
isRef: false,
elementType));
if (!isLastElement)
if (indexTemp is null)
{
// index = index + 1;
// span[0] = element; span[1] = element; etc.
expressions.Add(
new BoundAssignmentOperator(
expressionSyntax,
indexTemp,
_factory.Binary(BinaryOperatorKind.Addition, indexTemp.Type, indexTemp, _factory.Literal(1)),
_factory.Call(spanTemp, spanGetItem, _factory.Literal(currentElementIndex)),
rewrittenValue,
isRef: false,
indexTemp.Type));
elementType));
currentElementIndex++;
}
else
{
// span[index] = element;
expressions.Add(
new BoundAssignmentOperator(
expressionSyntax,
_factory.Call(spanTemp, spanGetItem, indexTemp),
rewrittenValue,
isRef: false,
elementType));
if (!isLastElement)
{
// index = index + 1;
expressions.Add(
new BoundAssignmentOperator(
expressionSyntax,
indexTemp,
_factory.Binary(BinaryOperatorKind.Addition, indexTemp.Type, indexTemp, _factory.Literal(1)),
isRef: false,
indexTemp.Type));
}
}
},
tryOptimizeSpreadElement: (ArrayBuilder<BoundExpression> sideEffects, BoundExpression spanTemp, BoundCollectionExpressionSpreadElement spreadElement, BoundExpression rewrittenSpreadOperand) =>
{
Debug.Assert(indexTemp is not null);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot have a similar comment here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment was already added in commit 38fdece at line 1270 (same location).


if (PrepareCopyToOptimization(spreadElement, rewrittenSpreadOperand) is not var (spanSliceMethod, spreadElementAsSpan, getLengthMethod, copyToMethod))
return false;

Expand Down
Loading