@@ -170,14 +170,9 @@ public static bool InlineIfPossible(Block block, int pos, ILTransformContext con
170170 public static bool InlineOneIfPossible ( Block block , int pos , InliningOptions options , ILTransformContext context )
171171 {
172172 context . CancellationToken . ThrowIfCancellationRequested ( ) ;
173- StLoc stloc = block . Instructions [ pos ] as StLoc ;
174- if ( stloc == null || stloc . Variable . Kind == VariableKind . PinnedLocal )
173+ if ( block . Instructions [ pos ] is not StLoc stloc )
175174 return false ;
176- ILVariable v = stloc . Variable ;
177- // ensure the variable is accessed only a single time
178- if ( v . StoreCount != 1 )
179- return false ;
180- if ( v . LoadCount > 1 || v . LoadCount + v . AddressCount != 1 )
175+ if ( ! VariableCanBeUsedForInlining ( stloc . Variable ) )
181176 return false ;
182177 // TODO: inlining of small integer types might be semantically incorrect,
183178 // but we can't avoid it this easily without breaking lots of tests.
@@ -186,6 +181,18 @@ public static bool InlineOneIfPossible(Block block, int pos, InliningOptions opt
186181 return InlineOne ( stloc , options , context ) ;
187182 }
188183
184+ public static bool VariableCanBeUsedForInlining ( ILVariable v )
185+ {
186+ if ( v . Kind == VariableKind . PinnedLocal )
187+ return false ;
188+ // ensure the variable is accessed only a single time
189+ if ( v . StoreCount != 1 )
190+ return false ;
191+ if ( v . LoadCount + v . AddressCount != 1 )
192+ return false ;
193+ return true ;
194+ }
195+
189196 /// <summary>
190197 /// Inlines the stloc instruction at block.Instructions[pos] into the next instruction.
191198 ///
@@ -908,6 +915,30 @@ public static bool CanMoveInto(ILInstruction expressionBeingMoved, ILInstruction
908915 return true ;
909916 }
910917
918+ /// <summary>
919+ /// Gets whether 'expressionBeingMoved' can be moved from somewhere before 'stmt' to become the replacement of 'targetLoad'.
920+ /// </summary>
921+ public static bool CanMoveIntoCallVirt ( ILInstruction expressionBeingMoved , ILInstruction stmt , CallVirt nestedCallVirt , ILInstruction targetLoad )
922+ {
923+ Debug . Assert ( targetLoad . IsDescendantOf ( stmt ) && nestedCallVirt . IsDescendantOf ( stmt ) ) ;
924+ ILInstruction thisArg = nestedCallVirt . Arguments [ 0 ] ;
925+ Debug . Assert ( thisArg is LdObjIfRef ) ;
926+ for ( ILInstruction inst = targetLoad ; inst != stmt ; inst = inst . Parent )
927+ {
928+ if ( ! inst . Parent . CanInlineIntoSlot ( inst . ChildIndex , expressionBeingMoved ) )
929+ return false ;
930+ // Check whether re-ordering with predecessors is valid:
931+ int childIndex = inst . ChildIndex ;
932+ for ( int i = 0 ; i < childIndex ; ++ i )
933+ {
934+ ILInstruction predecessor = inst . Parent . Children [ i ] ;
935+ if ( predecessor != thisArg && ! IsSafeForInlineOver ( predecessor , expressionBeingMoved ) )
936+ return false ;
937+ }
938+ }
939+ return true ;
940+ }
941+
911942 /// <summary>
912943 /// Gets whether arg can be un-inlined out of stmt.
913944 /// </summary>
0 commit comments