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

Commit514b536

Browse files
authored
Use runtime helperCreateSpan forstackalloc of non-byte arrays (#71261)
* Optimize non-byte stackalloc scenarios* Inline a variable* Inline a method* Use Binder helper to get well-known member* Visit everything in local rewriter* Clarify comment* Test non-blittable type* Fix nullability* Revert part that skips stack allocation* Align the data field* Test zero elements* Use indexer instead of `GetPinnableReference`* Reuse `IsTypeAllowedInBlobWrapper`* Emit `unaligned.` prefix* Test 2-byte primitive* Align to 8 bytes and omit `unaligned.` IL* Revert "Align to 8 bytes and omit `unaligned.` IL"This reverts commitae76846.
1 parentb011237 commit514b536

File tree

4 files changed

+813
-64
lines changed

4 files changed

+813
-64
lines changed

‎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: 74 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,27 @@
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
@@ -29,44 +33,97 @@ private void EmitStackAllocInitializers(TypeSymbol type, BoundArrayInitializatio
2933
varinitializationStyle=ShouldEmitBlockInitializerForStackAlloc(elementType,initExprs);
3034
if(initializationStyle==ArrayInitializerStyle.Element)
3135
{
36+
emitLocalloc();
3237
EmitElementStackAllocInitializers(elementType,initExprs,includeConstants:true);
3338
}
3439
else
3540
{
36-
ImmutableArray<byte>data=this.GetRawData(initExprs);
41+
boolmixedInitialized=false;
42+
43+
emitLocalloc();
44+
45+
varsizeInBytes=elementType.EnumUnderlyingTypeOrSelf().SpecialType.SizeInBytes();
46+
47+
ImmutableArray<byte>data=GetRawData(initExprs);
3748
if(data.All(datum=>datum==data[0]))
3849
{
3950
// All bytes are the same, no need for metadata blob, just initblk to fill it with the repeated value.
4051
_builder.EmitOpCode(ILOpCode.Dup);
4152
_builder.EmitIntConstant(data[0]);
4253
_builder.EmitIntConstant(data.Length);
4354
_builder.EmitOpCode(ILOpCode.Initblk,-3);
44-
45-
if(initializationStyle==ArrayInitializerStyle.Mixed)
46-
{
47-
EmitElementStackAllocInitializers(elementType,initExprs,includeConstants:false);
48-
}
4955
}
50-
elseif(elementType.EnumUnderlyingTypeOrSelf().SpecialType.SizeInBytes()==1)
56+
elseif(sizeInBytes==1)
5157
{
5258
// Initialize the stackalloc by copying the data from a metadata blob
5359
varfield=_builder.module.GetFieldForData(data,alignment:1,inits.Syntax,_diagnostics.DiagnosticBag);
5460
_builder.EmitOpCode(ILOpCode.Dup);
5561
_builder.EmitOpCode(ILOpCode.Ldsflda);
5662
_builder.EmitToken(field,inits.Syntax,_diagnostics.DiagnosticBag);
5763
_builder.EmitIntConstant(data.Length);
64+
_builder.EmitUnaligned(alignment:1);
5865
_builder.EmitOpCode(ILOpCode.Cpblk,-3);
59-
60-
if(initializationStyle==ArrayInitializerStyle.Mixed)
66+
}
67+
else
68+
{
69+
varsyntaxNode=inits.Syntax;
70+
if(Binder.GetWellKnownTypeMember(_module.Compilation,WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__CreateSpanRuntimeFieldHandle,_diagnostics,syntax:syntaxNode,isOptional:true)isMethodSymbolcreateSpanHelper&&
71+
Binder.GetWellKnownTypeMember(_module.Compilation,WellKnownMember.System_ReadOnlySpan_T__get_Item,_diagnostics,syntax:syntaxNode,isOptional:true)isMethodSymbolspanGetItemDefinition)
6172
{
62-
EmitElementStackAllocInitializers(elementType,initExprs,includeConstants:false);
73+
// Use RuntimeHelpers.CreateSpan and cpblk.
74+
varreadOnlySpan=spanGetItemDefinition.ContainingType.Construct(elementType);
75+
Debug.Assert(TypeSymbol.Equals(readOnlySpan.OriginalDefinition,_module.Compilation.GetWellKnownType(WellKnownType.System_ReadOnlySpan_T),TypeCompareKind.ConsiderEverything));
76+
varspanGetItem=spanGetItemDefinition.AsMember(readOnlySpan);
77+
78+
_builder.EmitOpCode(ILOpCode.Dup);
79+
80+
// ldtoken <PrivateImplementationDetails>...
81+
// call ReadOnlySpan<elementType> RuntimeHelpers::CreateSpan<elementType>(fldHandle)
82+
varfield=_builder.module.GetFieldForData(data,alignment:(ushort)sizeInBytes,syntaxNode,_diagnostics.DiagnosticBag);
83+
_builder.EmitOpCode(ILOpCode.Ldtoken);
84+
_builder.EmitToken(field,syntaxNode,_diagnostics.DiagnosticBag);
85+
_builder.EmitOpCode(ILOpCode.Call,0);
86+
varcreateSpanHelperReference=createSpanHelper.Construct(elementType).GetCciAdapter();
87+
_builder.EmitToken(createSpanHelperReference,syntaxNode,_diagnostics.DiagnosticBag);
88+
89+
vartemp=AllocateTemp(readOnlySpan,syntaxNode);
90+
_builder.EmitLocalStore(temp);
91+
_builder.EmitLocalAddress(temp);
92+
93+
// span.get_Item[0]
94+
_builder.EmitIntConstant(0);
95+
_builder.EmitOpCode(ILOpCode.Call,0);
96+
EmitSymbolToken(spanGetItem,syntaxNode,optArgList:null);
97+
98+
_builder.EmitIntConstant(data.Length);
99+
if(sizeInBytes!=8)
100+
{
101+
_builder.EmitUnaligned((sbyte)sizeInBytes);
102+
}
103+
_builder.EmitOpCode(ILOpCode.Cpblk,-3);
104+
105+
FreeTemp(temp);
106+
}
107+
else
108+
{
109+
EmitElementStackAllocInitializers(elementType,initExprs,includeConstants:true);
110+
mixedInitialized=true;
63111
}
64112
}
65-
else
113+
114+
if(initializationStyle==ArrayInitializerStyle.Mixed&&!mixedInitialized)
66115
{
67-
EmitElementStackAllocInitializers(elementType,initExprs,includeConstants:true);
116+
EmitElementStackAllocInitializers(elementType,initExprs,includeConstants:false);
68117
}
69118
}
119+
120+
voidemitLocalloc()
121+
{
122+
EmitExpression(count,used:true);
123+
124+
_sawStackalloc=true;
125+
_builder.EmitOpCode(ILOpCode.Localloc);
126+
}
70127
}
71128

72129
privateArrayInitializerStyleShouldEmitBlockInitializerForStackAlloc(TypeSymbolelementType,ImmutableArray<BoundExpression>inits)
@@ -78,7 +135,7 @@ private ArrayInitializerStyle ShouldEmitBlockInitializerForStackAlloc(TypeSymbol
78135
returnArrayInitializerStyle.Element;
79136
}
80137

81-
if(elementType.EnumUnderlyingTypeOrSelf().SpecialType.IsBlittable())
138+
if(IsTypeAllowedInBlobWrapper(elementType.EnumUnderlyingTypeOrSelf().SpecialType))
82139
{
83140
intinitCount=0;
84141
intconstCount=0;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp