Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit5261199

Browse files
committed
Optimize non-byte stackalloc scenarios
1 parent8c38000 commit5261199

File tree

10 files changed

+514
-37
lines changed

10 files changed

+514
-37
lines changed

‎src/Compilers/CSharp/Portable/CodeGen/EmitArrayInitializer.cs‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ private void EmitArrayInitializers(ArrayTypeSymbol arrayType, BoundArrayInitiali
5252
}
5353
else
5454
{
55-
ImmutableArray<byte>data=this.GetRawData(initExprs);
55+
ImmutableArray<byte>data=GetRawData(initExprs);
5656

5757
_builder.EmitArrayBlockInitializer(data,inits.Syntax,_diagnostics.DiagnosticBag);
5858

@@ -328,7 +328,7 @@ private void InitializerCountRecursive(ImmutableArray<BoundExpression> inits, re
328328
/// Produces a serialized blob of all constant initializers.
329329
/// Non-constant initializers are matched with a zero of corresponding size.
330330
/// </summary>
331-
privateImmutableArray<byte>GetRawData(ImmutableArray<BoundExpression>initializers)
331+
privatestaticImmutableArray<byte>GetRawData(ImmutableArray<BoundExpression>initializers)
332332
{
333333
// the initial size is a guess.
334334
// there is no point to be precise here as MemoryStream always has N + 1 storage
@@ -340,7 +340,7 @@ private ImmutableArray<byte> GetRawData(ImmutableArray<BoundExpression> initiali
340340
returnwriter.ToImmutableArray();
341341
}
342342

343-
privatevoidSerializeArrayRecursive(BlobBuilderbw,ImmutableArray<BoundExpression>inits)
343+
privatestaticvoidSerializeArrayRecursive(BlobBuilderbw,ImmutableArray<BoundExpression>inits)
344344
{
345345
if(inits.Length!=0)
346346
{

‎src/Compilers/CSharp/Portable/CodeGen/EmitExpression.cs‎

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2367,24 +2367,18 @@ private void EmitArrayCreationExpression(BoundArrayCreation expression, bool use
23672367

23682368
privatevoidEmitConvertedStackAllocExpression(BoundConvertedStackAllocExpressionexpression,boolused)
23692369
{
2370-
EmitExpression(expression.Count,used);
2371-
2372-
// the only sideeffect of a localloc is a nondeterministic and generally fatal StackOverflow.
2373-
// we can ignore that if the actual result is unused
2370+
varinitializer=expression.InitializerOpt;
23742371
if(used)
23752372
{
2376-
_sawStackalloc=true;
2377-
_builder.EmitOpCode(ILOpCode.Localloc);
2373+
EmitStackAlloc(expression.Type,initializer,expression.Count);
23782374
}
2379-
2380-
varinitializer=expression.InitializerOpt;
2381-
if(initializer!=null)
2375+
else
23822376
{
2383-
if(used)
2384-
{
2385-
EmitStackAllocInitializers(expression.Type,initializer);
2386-
}
2387-
else
2377+
// the only sideeffect of a localloc is a nondeterministic and generally fatal StackOverflow.
2378+
// we can ignore that if the actual result is unused
2379+
EmitExpression(expression.Count,used:false);
2380+
2381+
if(initializer!=null)
23882382
{
23892383
// If not used, just emit initializer elements to preserve possible sideeffects
23902384
foreach(varinitininitializer.Initializers)

‎src/Compilers/CSharp/Portable/CodeGen/EmitStackAllocInitializer.cs‎

Lines changed: 94 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,50 +2,72 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33
// See the LICENSE file in the project root for more information.
44

5-
#nullable disable
6-
75
usingSystem;
86
usingSystem.Collections.Immutable;
97
usingSystem.Diagnostics;
108
usingSystem.Linq;
119
usingSystem.Reflection.Metadata;
1210
usingMicrosoft.CodeAnalysis.CSharp.Symbols;
13-
usingMicrosoft.CodeAnalysis.PooledObjects;
1411

1512
namespaceMicrosoft.CodeAnalysis.CSharp.CodeGen
1613
{
1714
internalpartialclassCodeGenerator
1815
{
19-
privatevoidEmitStackAllocInitializers(TypeSymboltype,BoundArrayInitializationinits)
16+
privatevoidEmitStackAlloc(TypeSymboltype,BoundArrayInitialization?inits,BoundExpressioncount)
2017
{
18+
if(initsisnull)
19+
{
20+
emitLocalloc();
21+
return;
22+
}
23+
2124
Debug.Assert(typeisPointerTypeSymbol||typeisNamedTypeSymbol);
25+
Debug.Assert(_diagnostics.DiagnosticBagis notnull);
2226

2327
varelementType=(type.TypeKind==TypeKind.Pointer
2428
?((PointerTypeSymbol)type).PointedAtTypeWithAnnotations
2529
:((NamedTypeSymbol)type).TypeArgumentsWithAnnotationsNoUseSiteDiagnostics[0]).Type;
2630

31+
boolisReadOnlySpan=TypeSymbol.Equals(
32+
(typeasNamedTypeSymbol)?.OriginalDefinition,_module.Compilation.GetWellKnownType(WellKnownType.System_ReadOnlySpan_T),TypeCompareKind.ConsiderEverything);
33+
2734
varinitExprs=inits.Initializers;
2835

29-
varinitializationStyle=ShouldEmitBlockInitializerForStackAlloc(elementType,initExprs);
30-
if(initializationStyle==ArrayInitializerStyle.Element)
36+
boolisEncDelta=_module.IsEncDelta;
37+
varinitializationStyle=ShouldEmitBlockInitializerForStackAlloc(elementType,initExprs,isEncDelta);
38+
39+
if(isReadOnlySpan)
3140
{
41+
varcreateSpanHelper=getCreateSpanHelper(_module,elementType);
42+
43+
// ROS<T> is only used here if it has already been decided to use CreateSpan
44+
Debug.Assert(createSpanHelperis notnull);
45+
Debug.Assert(UseCreateSpanForReadOnlySpanStackAlloc(elementType,inits,isEncDelta:isEncDelta));
46+
47+
EmitExpression(count,used:false);
48+
49+
ImmutableArray<byte>data=GetRawData(initExprs);
50+
_builder.EmitCreateSpan(data,createSpanHelper,inits.Syntax,_diagnostics.DiagnosticBag);
51+
}
52+
elseif(initializationStyle==ArrayInitializerStyle.Element)
53+
{
54+
emitLocalloc();
3255
EmitElementStackAllocInitializers(elementType,initExprs,includeConstants:true);
3356
}
3457
else
3558
{
36-
ImmutableArray<byte>data=this.GetRawData(initExprs);
59+
boolmixedInitialized=false;
60+
61+
emitLocalloc();
62+
63+
ImmutableArray<byte>data=GetRawData(initExprs);
3764
if(data.All(datum=>datum==data[0]))
3865
{
3966
// All bytes are the same, no need for metadata blob, just initblk to fill it with the repeated value.
4067
_builder.EmitOpCode(ILOpCode.Dup);
4168
_builder.EmitIntConstant(data[0]);
4269
_builder.EmitIntConstant(data.Length);
4370
_builder.EmitOpCode(ILOpCode.Initblk,-3);
44-
45-
if(initializationStyle==ArrayInitializerStyle.Mixed)
46-
{
47-
EmitElementStackAllocInitializers(elementType,initExprs,includeConstants:false);
48-
}
4971
}
5072
elseif(elementType.EnumUnderlyingTypeOrSelf().SpecialType.SizeInBytes()==1)
5173
{
@@ -56,22 +78,74 @@ private void EmitStackAllocInitializers(TypeSymbol type, BoundArrayInitializatio
5678
_builder.EmitToken(field,inits.Syntax,_diagnostics.DiagnosticBag);
5779
_builder.EmitIntConstant(data.Length);
5880
_builder.EmitOpCode(ILOpCode.Cpblk,-3);
59-
60-
if(initializationStyle==ArrayInitializerStyle.Mixed)
81+
}
82+
else
83+
{
84+
if(getCreateSpanHelper(_module,elementType)is{}createSpanHelper&&
85+
_module.Compilation.GetWellKnownTypeMember(WellKnownMember.System_ReadOnlySpan_T__GetPinnableReference)isMethodSymbolgetPinnableReference)
6186
{
62-
EmitElementStackAllocInitializers(elementType,initExprs,includeConstants:false);
87+
// Use RuntimeHelpers.CreateSpan and cpblk.
88+
EmitStackAllocBlockMultiByteInitializer(data,createSpanHelper,getPinnableReference,elementType,inits.Syntax,_diagnostics.DiagnosticBag);
89+
}
90+
else
91+
{
92+
EmitElementStackAllocInitializers(elementType,initExprs,includeConstants:true);
93+
mixedInitialized=true;
6394
}
6495
}
65-
else
96+
97+
if(initializationStyle==ArrayInitializerStyle.Mixed&&!mixedInitialized)
6698
{
67-
EmitElementStackAllocInitializers(elementType,initExprs,includeConstants:true);
99+
EmitElementStackAllocInitializers(elementType,initExprs,includeConstants:false);
68100
}
69101
}
102+
103+
voidemitLocalloc()
104+
{
105+
EmitExpression(count,used:true);
106+
107+
_sawStackalloc=true;
108+
_builder.EmitOpCode(ILOpCode.Localloc);
109+
}
110+
111+
staticCci.IMethodReference?getCreateSpanHelper(Emit.PEModuleBuildermodule,TypeSymbolelementType)
112+
{
113+
varmember=module.Compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__CreateSpanRuntimeFieldHandle);
114+
return((MethodSymbol?)member)?.Construct(elementType).GetCciAdapter();
115+
}
116+
}
117+
118+
privatevoidEmitStackAllocBlockMultiByteInitializer(ImmutableArray<byte>data,Cci.IMethodReferencecreateSpanHelper,MethodSymbolgetPinnableReferenceDefinition,TypeSymbolelementType,SyntaxNodesyntaxNode,DiagnosticBagdiagnostics)
119+
{
120+
varreadOnlySpan=getPinnableReferenceDefinition.ContainingType.Construct(elementType);
121+
Debug.Assert(TypeSymbol.Equals(readOnlySpan.OriginalDefinition,_module.Compilation.GetWellKnownType(WellKnownType.System_ReadOnlySpan_T),TypeCompareKind.ConsiderEverything));
122+
vargetPinnableReference=getPinnableReferenceDefinition.AsMember(readOnlySpan);
123+
124+
_builder.EmitOpCode(ILOpCode.Dup);
125+
_builder.EmitCreateSpan(data,createSpanHelper,syntaxNode,diagnostics);
126+
127+
vartemp=AllocateTemp(readOnlySpan,syntaxNode);
128+
_builder.EmitLocalStore(temp);
129+
_builder.EmitLocalAddress(temp);
130+
131+
_builder.EmitOpCode(ILOpCode.Call,0);
132+
EmitSymbolToken(getPinnableReference,syntaxNode,optArgList:null);
133+
_builder.EmitIntConstant(data.Length);
134+
_builder.EmitOpCode(ILOpCode.Cpblk,-3);
135+
136+
FreeTemp(temp);
137+
}
138+
139+
internalstaticboolUseCreateSpanForReadOnlySpanStackAlloc(TypeSymbolelementType,BoundArrayInitialization?inits,boolisEncDelta)
140+
{
141+
returninits?.Initializersis{}initExprs&&
142+
elementType.EnumUnderlyingTypeOrSelf().SpecialType.SizeInBytes()>=1&&
143+
ShouldEmitBlockInitializerForStackAlloc(elementType,initExprs,isEncDelta)==ArrayInitializerStyle.Block;
70144
}
71145

72-
privateArrayInitializerStyleShouldEmitBlockInitializerForStackAlloc(TypeSymbolelementType,ImmutableArray<BoundExpression>inits)
146+
privatestaticArrayInitializerStyleShouldEmitBlockInitializerForStackAlloc(TypeSymbolelementType,ImmutableArray<BoundExpression>inits,boolisEncDelta)
73147
{
74-
if(_module.IsEncDelta)
148+
if(isEncDelta)
75149
{
76150
// Avoid using FieldRva table. Can be allowed if tested on all supported runtimes.
77151
// Consider removing: https://github.com/dotnet/roslyn/issues/69480
@@ -103,7 +177,7 @@ private ArrayInitializerStyle ShouldEmitBlockInitializerForStackAlloc(TypeSymbol
103177
returnArrayInitializerStyle.Element;
104178
}
105179

106-
privatevoidStackAllocInitializerCount(ImmutableArray<BoundExpression>inits,refintinitCount,refintconstInits)
180+
privatestaticvoidStackAllocInitializerCount(ImmutableArray<BoundExpression>inits,refintinitCount,refintconstInits)
107181
{
108182
if(inits.Length==0)
109183
{

‎src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Conversion.cs‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,16 @@ public override BoundNode VisitConversion(BoundConversion node)
6868

6969
varrewrittenType=VisitType(node.Type);
7070

71+
// special handling for initializers converted to ROS<T>
72+
if(node.OperandisBoundConvertedStackAllocExpressionstackAllocExpression&&
73+
TypeSymbol.Equals(rewrittenType.OriginalDefinition,_compilation.GetWellKnownType(WellKnownType.System_ReadOnlySpan_T),TypeCompareKind.ConsiderEverything)&&
74+
_compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__CreateSpanRuntimeFieldHandle)is notnull&&
75+
CodeGen.CodeGenerator.UseCreateSpanForReadOnlySpanStackAlloc(stackAllocExpression.ElementType,stackAllocExpression.InitializerOpt,isEncDelta:this.EmitModule?.IsEncDelta==true))
76+
{
77+
varcount=VisitExpression(stackAllocExpression.Count);
78+
returnnewBoundConvertedStackAllocExpression(node.Operand.Syntax,stackAllocExpression.ElementType,count,stackAllocExpression.InitializerOpt,rewrittenType);
79+
}
80+
7181
boolwasInExpressionLambda=_inExpressionLambda;
7282
_inExpressionLambda=_inExpressionLambda||(node.ConversionKind==ConversionKind.AnonymousFunction&&!wasInExpressionLambda&&rewrittenType.IsExpressionTree());
7383
InstrumentationState.IsSuppressed=_inExpressionLambda;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp