Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JIT: Fold unreachable cases for switch in importer. #82793

Merged
merged 3 commits into from
Mar 15, 2023

Conversation

JulieLeeMSFT
Copy link
Member

@JulieLeeMSFT JulieLeeMSFT commented Feb 28, 2023

This PR folds unreachable cases in Switch early in Import phase when switch value is GT_CNT_INT.
Fixes #65368.

Below trees show the optimization example for the below scenario:

static void Foo() => Bar(3);

static void Bar(int i)
{
    switch (i)
    {
        case 0:
            Console.WriteLine();
            break;
        case 1:
            Console.WriteLine();
            break;
        case 2:
            Console.WriteLine();
            break;
        case 3:
            Console.WriteLine();
            break;
        case 4:
            Console.WriteLine();
            break;
        case 5:
            // no-op
            break;
    }
}
  • Trees before Switch folding:
*************** Inline @[000003] Finishing PHASE Profile incorporation
Trees after Profile incorporation

-----------------------------------------------------------------------------------------------------------------------------------------
BBnum BBid ref try hnd preds           weight    lp [IL range]     [jump]      [EH region]         [flags]
-----------------------------------------------------------------------------------------------------------------------------------------
BB03 [0002]  1                             1       [000..01E)-> BB05,BB06,BB07,BB08,BB09,BB10,BB04[def] (switch)                     
BB04 [0003]  1       BB03                  1       [01E..01F)        (return)                     
BB05 [0004]  1       BB03                  1       [01F..025)        (return)                     
BB06 [0005]  1       BB03                  1       [025..02B)        (return)                     
BB07 [0006]  1       BB03                  1       [02B..031)        (return)                     
BB08 [0007]  1       BB03                  1       [031..037)        (return)                     
BB09 [0008]  1       BB03                  1       [037..03C)                                     
BB10 [0009]  2       BB03,BB09             1       [03C..03D)        (return)                     
-----------------------------------------------------------------------------------------------------------------------------------------
  • After Importation, BB03 always jumps to BB08 and other basic blocks are folded away:
*************** Inline @[000003] Finishing PHASE Importation
Trees after Importation

-----------------------------------------------------------------------------------------------------------------------------------------
BBnum BBid ref try hnd preds           weight    lp [IL range]     [jump]      [EH region]         [flags]
-----------------------------------------------------------------------------------------------------------------------------------------
BB03 [0002]  1                             1       [000..01E)-> BB08 (always)                     i 
BB04 [0003]  0                             1       [01E..01F)        (return)                     
BB05 [0004]  0                             1       [01F..025)        (return)                     
BB06 [0005]  0                             1       [025..02B)        (return)                     
BB07 [0006]  0                             1       [02B..031)        (return)                     
BB08 [0007]  1       BB03                  1       [031..037)        (return)                     i 
BB09 [0008]  0                             1       [037..03C)                                     
BB10 [0009]  1       BB09                  1       [03C..03D)        (return)                     
-----------------------------------------------------------------------------------------------------------------------------------------
*************** Before renumbering the basic blocks

-----------------------------------------------------------------------------------------------------------------------------------------
BBnum BBid ref try hnd preds           weight    lp [IL range]     [jump]      [EH region]         [flags]
-----------------------------------------------------------------------------------------------------------------------------------------
BB03 [0002]  1                             1       [000..01E)-> BB08 (always)                     i 
BB08 [0007]  1       BB03                  1       [031..037)        (return)                     i 
-----------------------------------------------------------------------------------------------------------------------------------------

***************  Exception Handling table is empty
Renumber BB08 to BB04
*************** Inline @[000003] Finishing PHASE Post-import
Trees after Post-import

-----------------------------------------------------------------------------------------------------------------------------------------
BBnum BBid ref try hnd preds           weight    lp [IL range]     [jump]      [EH region]         [flags]
-----------------------------------------------------------------------------------------------------------------------------------------
BB03 [0002]  1                             1       [000..01E)-> BB04 (always)                     i 
BB04 [0007]  1       BB03                  1       [031..037)        (return)                     i 
-----------------------------------------------------------------------------------------------------------------------------------------

------------ BB03 [000..01E) -> BB04 (always), preds={} succs={BB04}

***** BB03
STMT00003 ( 0x000[E-] ... ??? ) <- INL01 @ 0x000[E-] <- INLRT @ 0x000[E-]
               [000006] -----------                         *  NOP       void  

------------ BB04 [031..037) (return), preds={BB03} succs={}

***** BB04
STMT00004 ( 0x031[E-] ... ??? ) <- INL01 @ 0x000[E-] <- INLRT @ 0x000[E-]
               [000007] --C-G------                         *  CALL      void   System.Console:WriteLine()

@dotnet-issue-labeler dotnet-issue-labeler bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Feb 28, 2023
@ghost ghost assigned JulieLeeMSFT Feb 28, 2023
@ghost
Copy link

ghost commented Feb 28, 2023

Tagging subscribers to this area: @JulieLeeMSFT, @jakobbotsch, @kunalspathak
See info in area-owners.md if you want to be subscribed.

Issue Details

Draft PR.

Author: JulieLeeMSFT
Assignees: -
Labels:

area-CodeGen-coreclr

Milestone: -

@JulieLeeMSFT JulieLeeMSFT added this to the 8.0.0 milestone Feb 28, 2023
@AndyAyersMS
Copy link
Member

@JulieLeeMSFT is this ready for review?

@AndyAyersMS
Copy link
Member

Diffs show some unexpected size increases, eg

;; x64 windows libraries_tests.pmi.windows.x64.checked.mch

Top method regressions (percentages):
         800 (37.54 % of base) : 175521.dasm - System.Runtime.Serialization.Xml.XsdDataContractExporterTests.ExporterApiTests+<>c:<Export_MemberData>b__7_7(System.String,System.Xml.Schema.XmlSchemaSet):this
         630 (37.21 % of base) : 57285.dasm - System.Text.Json.Serialization.Tests.PolymorphicTests:<NestedObjectAsRootObject>g__Verify|6_0(System.String)
         420 (31.37 % of base) : 56898.dasm - System.Text.Json.Serialization.Tests.NullTests:NullReferences()

Can you investigate?

Also some diffs in minopts which we probably don't want.

@JulieLeeMSFT
Copy link
Member Author

Yes, I am working on it.

Can you investigate?

/* Pop the switch value off the stack */
op1 = impPopStack().val;
assertImp(genActualTypeIsIntOrI(op1->TypeGet()));

/* We can create a switch node */
// Fold Switch for GT_CNS_INT
if ((op1->gtOper == GT_CNS_INT) && !compIsForImportOnly())
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if ((op1->gtOper == GT_CNS_INT) && !compIsForImportOnly())
if (opts.OptimizationEnabled() && (op1->gtOper == GT_CNS_INT) && !compIsForImportOnly())

We don't want to do this unless we're optimizing the method.

This should fix the diffs you are seeing with minopts.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

/* Pop the switch value off the stack */
op1 = impPopStack().val;
assertImp(genActualTypeIsIntOrI(op1->TypeGet()));

/* We can create a switch node */
// Fold Switch for GT_CNS_INT
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should try constant-folding the op1 here, to increase the number of times we see constants.

                op1 = gtFoldExpr(impPopStack().val);

(replace line 8004 above)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

printf(" to " FMT_BB, block->bbJumpDest->bbNum);
}
printf("\n");
fgDispBasicBlocks(true);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We probably don't need to show all BBs here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed.

@JulieLeeMSFT
Copy link
Member Author

Diff

Size: -6216/+10973 
Throughput: up to -0.06% (improved)

image
image

@JulieLeeMSFT
Copy link
Member Author

Size regressions are good diffs or incidental changes. So, all look good. Some examples:

  • Case 1: In diff, some inlines in Switch arm got folded away. And, later there are inlines in the diff that were not done in the base becasue the diff compiler did not do those extra inlines, it has fewer local vars, and that made a later inline more attractive. So, this is good diffs.
    image
  • Case 2: 2 jumps are removed. So, it is a good diff.
    image
  • Case 3: Incidental size increase due to removed "SHORT".
    image

@JulieLeeMSFT
Copy link
Member Author

JulieLeeMSFT commented Mar 14, 2023

@AndyAyersMS, it is ready for review.
CC @dotnet/jit-contrib.
All tests passed in the commit f9b19b7.

Diffs

Copy link
Member

@AndyAyersMS AndyAyersMS left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

@JulieLeeMSFT JulieLeeMSFT merged commit 8ab7a2f into dotnet:main Mar 15, 2023
@JulieLeeMSFT JulieLeeMSFT deleted the 65368 branch March 15, 2023 16:15
@ghost ghost locked as resolved and limited conversation to collaborators Apr 14, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
Projects
None yet
Development

Successfully merging this pull request may close these issues.

JIT: fold unreachable cases for switch
2 participants