Skip to content

Commit

Permalink
Use the known length int constructor if available when lowering colle…
Browse files Browse the repository at this point in the history
…ction expressions
  • Loading branch information
jbevain committed Mar 6, 2024
1 parent 8915842 commit 05c5f8e
Show file tree
Hide file tree
Showing 6 changed files with 770 additions and 841 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -867,24 +867,22 @@ private BoundExpression CreateAndPopulateList(BoundCollectionExpression node, Ty
bool useKnownLength = ShouldUseKnownLength(node, out numberIncludingLastSpread);
RewriteCollectionExpressionElementsIntoTemporaries(elements, numberIncludingLastSpread, localsBuilder, sideEffects);

bool useOptimizations = false;
MethodSymbol? setCount = null;
bool useOptimization = false;
MethodSymbol? asSpan = null;

// Do not use optimizations in async method since the optimizations require Span<T>.
// Do not use optimization in async method since the optimization require Span<T>.
if (useKnownLength && elements.Length > 0 && _factory.CurrentFunction?.IsAsync == false)
{
setCount = ((MethodSymbol?)_compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_InteropServices_CollectionsMarshal__SetCount_T))?.Construct(typeArguments);
asSpan = ((MethodSymbol?)_compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_InteropServices_CollectionsMarshal__AsSpan_T))?.Construct(typeArguments);

if (setCount is { } && asSpan is { })
if (asSpan is { })
{
useOptimizations = true;
useOptimization = true;
}
}

BoundObjectCreationExpression rewrittenReceiver;
if (useKnownLength && elements.Length > 0 && !useOptimizations)
if (useKnownLength && elements.Length > 0)
{
// List<ElementType> list = new(N + s1.Length + ...);
var constructor = ((MethodSymbol)_factory.WellKnownMember(WellKnownMember.System_Collections_Generic_List_T__ctorInt32)).AsMember(collectionType);
Expand All @@ -903,16 +901,11 @@ private BoundExpression CreateAndPopulateList(BoundCollectionExpression node, Ty
localsBuilder.Add(listTemp);
sideEffects.Add(assignmentToTemp);

// Use Span<T> if CollectionsMarshal methods are available, otherwise use List<T>.Add().
if (useOptimizations)
// Use Span<T> if CollectionsMarshal.AsSpan is available, otherwise use List<T>.Add().
if (useOptimization)
{
Debug.Assert(useKnownLength);
Debug.Assert(setCount is { });
Debug.Assert(asSpan is { });

// CollectionsMarshal.SetCount<ElementType>(list, N + s1.Length + ...);
sideEffects.Add(_factory.Call(receiver: null, setCount, listTemp, GetKnownLengthExpression(elements, numberIncludingLastSpread, localsBuilder)));

// var span = CollectionsMarshal.AsSpan<ElementType(list);
BoundLocal spanTemp = _factory.StoreToTemp(_factory.Call(receiver: null, asSpan, listTemp), out assignmentToTemp, isKnownToReferToTempIfReferenceType: true);
localsBuilder.Add(spanTemp);
Expand Down
Loading

0 comments on commit 05c5f8e

Please sign in to comment.