Skip to content

A simple method that performs unboxing is considered unprofitable inlinee, preventing box stack allocation #104479

Closed
@neon-sunset

Description

@neon-sunset

Description

Given the following code:

static int BoxTest()
{
    var boxed = (object)42;
    Unbox(boxed);
    return 42;
}

static void Unbox(object value)
{
    var number = (int)value;
    Consume(number.ToString());
}

[MethodImpl(MethodImplOptions.NoInlining)]
static void Consume<T>(T value) { }

It appears that Unbox(object) method is considered an unprofitable inlinee, leading to the following codegen:

G_M15828_IG01:  ;; offset=0x0000
       sub      rsp, 40
						;; size=4 bbWeight=1 PerfScore 0.25
G_M15828_IG02:  ;; offset=0x0004
       mov      rcx, 0x7FF9616B5A58      ; System.Int32
       call     CORINFO_HELP_NEWSFAST
       mov      dword ptr [rax+0x08], 42
       mov      rcx, rax
       call     [Program:<<Main>$>g__Unbox|0_1(System.Object)]
       mov      eax, 42
						;; size=36 bbWeight=1 PerfScore 5.75
G_M15828_IG03:  ;; offset=0x0028
       add      rsp, 40
       ret

If we annotate Unbox with AggressiveInlining, it gets inlined with allocation being elided as expected:

G_M15828_IG01:  ;; offset=0x0000
       sub      rsp, 40
						;; size=4 bbWeight=1 PerfScore 0.25
G_M15828_IG02:  ;; offset=0x0004
       mov      ecx, 42
       call     [System.Number:Int32ToDecStr(int):System.String]
       mov      rdx, rax
       mov      rcx, 0x7FF9DCB36110      ; Program:<<Main>$>g__Consume|0_2[System.String](System.String)
       call     [Program:<<Main>$>g__Consume|0_2[System.__Canon](System.__Canon)]
       mov      eax, 42
						;; size=35 bbWeight=1 PerfScore 7.00
G_M15828_IG03:  ;; offset=0x0027
       add      rsp, 40
       ret

Data

PHASE Morph - Inlining

*************** Starting PHASE Morph - Inlining
Expanding INLINE_CANDIDATE in statement STMT00002 in BB01:
STMT00002 ( ??? ... ??? )
               [000010] I-C-G------                         *  CALL      void   Program:<<Main>$>g__Unbox|0_1(System.Object) (exactContextHnd=0x00007FF9DA234E59)
               [000009] ----------- arg0                    \--*  BOX       ref   
               [000008] -----------                            \--*  LCL_VAR   ref    V01 tmp1         

Argument #0:
               [000009] -----------                         *  BOX       ref   
               [000008] -----------                         \--*  LCL_VAR   ref    V01 tmp1         

INLINER: inlineInfo.tokenLookupContextHandle for Program:<<Main>$>g__Unbox|0_1(System.Object) set to 0x00007FF9DA234E59:

Invoking compiler for the inlinee method Program:<<Main>$>g__Unbox|0_1(System.Object) :
IL to import:
IL_0000  02                ldarg.0     
IL_0001  a5 52 00 00 01    unbox.any    0x1000052
IL_0006  0a                stloc.0     
IL_0007  12 00             ldloca.s     0x0
IL_0009  28 48 00 00 0a    call         0xA000048
IL_000e  28 02 00 00 2b    call         0x2B000002
IL_0013  2a                ret         

INLINER impTokenLookupContextHandle for Program:<<Main>$>g__Unbox|0_1(System.Object) is 0x00007FF9DA234E59.
*************** In compInitDebuggingInfo() for Program:<<Main>$>g__Unbox|0_1(System.Object)
info.compStmtOffsetsCount    = 0
info.compStmtOffsetsImplicit = 0005h ( STACK_EMPTY CALL_SITE )
*************** In fgFindBasicBlocks() for Program:<<Main>$>g__Unbox|0_1(System.Object)
weight= 10 : state   3 [ ldarg.0 ]
weight=274 : state 142 [ unbox.any ]
weight=  6 : state  11 [ stloc.0 ]
weight= 35 : state 189 [ ldloca.s.normed ]
weight= 79 : state  40 [ call ]
weight= 79 : state  40 [ call ]
weight= 19 : state  42 [ ret ]

Inline candidate looks like a wrapper method.  Multiplier increased to 1.
Callsite is going to box 1 arguments.  Multiplier increased to 1.5.
Inline candidate callsite is boring.  Multiplier increased to 2.8.
calleeNativeSizeEstimate=502
callsiteNativeSizeEstimate=85
benefit multiplier=2.8
threshold=237
Native estimate for function size exceeds threshold for inlining 50.2 > 23.7 (multiplier = 2.8)


Inline expansion aborted, inline not profitable
INLINER: during 'fgInline' result 'failed this call site' reason 'unprofitable inline' for 'Program:<<Main>$>g__BoxTest|0_0():int' calling 'Program:<<Main>$>g__Unbox|0_1(System.Object)'
INLINER: during 'fgInline' result 'failed this call site' reason 'unprofitable inline'
**************** Inline Tree

Inlines into 06000003 [via ExtendedDefaultPolicy] Program:<<Main>$>g__BoxTest|0_0():int:
  [INL00 IL=0007 TR=000010 06000004] [FAILED: call site: unprofitable inline] Program:<<Main>$>g__Unbox|0_1(System.Object)
Budget: initialTime=105, finalTime=105, initialBudget=1050, currentBudget=1050
Budget: initialSize=473, finalSize=473

*************** Before renumbering the basic blocks

---------------------------------------------------------------------------------------------------------------------------------------------------------------------
BBnum BBid ref try hnd preds           weight   [IL range]   [jump]                            [EH region]        [flags]
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
BB01 [0000]  1                             1    [000..00F)                           (return)                     i newobj
---------------------------------------------------------------------------------------------------------------------------------------------------------------------

***************  Exception Handling table is empty
=============== No blocks renumbered!

*************** Finishing PHASE Morph - Inlining

Configuration

Windows 11, x64, runtime commit ebf21a4

Regression?

No

Metadata

Metadata

Assignees

Labels

area-CodeGen-coreclrCLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMIin-prThere is an active PR which will close this issue when it is mergedtenet-performancePerformance related issue

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions