Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.

JIT: cleanup redundant exact type tests #27397

Conversation

AndyAyersMS
Copy link
Member

Generate exact type assertions from exact type tests in the IR. Look for these
assertions and set the value number for RELOPs with known outcomes. Process
JTRUE nodes in the main assertion prop optimization loop.

This combination of changes removes residual exact type tests from cast
expansions when they are anticipated by user inserted exact type tests, as in:

    if (b.GetType() == typeof(D))
    {
        return (D)b;
    }

Closes #14471.

Generate exact type assertions from exact type tests in the IR. Look for these
assertions and set the value number for RELOPs with known outcomes. Process
JTRUE nodes in the main assertion prop optimization loop.

This combination of changes removes residual exact type tests from cast
expansions when they are anticipated by user inserted exact type tests, as in:

```C#
    if (b.GetType() == typeof(D))
    {
        return (D)b;
    }
```

Closes #14471.
@AndyAyersMS
Copy link
Member Author

@dotnet/jit-contrib PTAL

diffs:

Summary:
(Lower is better)

Total bytes of diff: -2080 (-0.01% of base)
    diff is an improvement.

Top file improvements by size (bytes):
        -432 : xunit.assert.dasm (-0.35% of base)
        -432 : xunit.core.dasm (-0.66% of base)
        -432 : xunit.execution.dotnet.dasm (-0.19% of base)
        -318 : System.Data.Common.dasm (-0.02% of base)
        -221 : System.Security.Cryptography.X509Certificates.dasm (-0.13% of base)

8 total files with size differences (8 improved, 0 regressed), 121 unchanged.

Top method improvements by size (bytes):
        -318 (-28.22% of base) : System.Data.Common.dasm - BigIntegerStorage:ConvertToBigInteger(ref,ref):struct
        -130 (-2.22% of base) : System.Private.CoreLib.dasm - Dictionary`2:.ctor(ref,ref):this (14 methods)
         -97 (-2.11% of base) : System.Security.AccessControl.dasm - CommonAcl:RemoveQualifiedAces(ref,int,int,ubyte,bool,int,struct,struct):bool:this
         -72 (-4.89% of base) : xunit.assert.dasm - AssertEqualityComparer`1:Equals(ubyte,ubyte):bool:this
         -72 (-4.82% of base) : xunit.assert.dasm - AssertEqualityComparer`1:Equals(short,short):bool:this

Top method improvements by size (percentage):
        -318 (-28.22% of base) : System.Data.Common.dasm - BigIntegerStorage:ConvertToBigInteger(ref,ref):struct
         -36 (-27.07% of base) : System.Security.Cryptography.X509Certificates.dasm - FindPal:ConfirmedCast(ref):int
         -36 (-26.87% of base) : System.Security.Cryptography.X509Certificates.dasm - FindPal:ConfirmedCast(ref):ubyte
         -36 (-26.87% of base) : System.Security.Cryptography.X509Certificates.dasm - FindPal:ConfirmedCast(ref):long
         -41 (-26.80% of base) : System.Security.Cryptography.X509Certificates.dasm - FindPal:ConfirmedCast(ref):struct

28 total methods with size differences (28 improved, 0 regressed), 203097 unchanged.

on an example like the one in #14471, we now generate:

G_M62121_IG01:

G_M62121_IG02:
       mov      rax, 0xD1FFAB1E
       cmp      qword ptr [rcx], rax
       jne      SHORT G_M62121_IG05

G_M62121_IG03:		;; bbWeight=0.50
       mov      rax, rcx

G_M62121_IG04:		;; bbWeight=0.50
       ret      

G_M62121_IG05:		;; bbWeight=0.50
       xor      rax, rax

G_M62121_IG06:		;; bbWeight=0.50
       ret      

{
GenTreeIndir* indir = op1->AsIndir();

if (!indir->HasIndex() && (indir->Offset() == 0))
Copy link

Choose a reason for hiding this comment

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

I don't think you should use GenTreeIndir's HasIndex, Base and Offset. These are practically meaningless before lowering because they depend on containment and address modes. Before lowering:

  • HasIndex() is always false
  • Base() is just Addr()
  • Offset() is always 0
    Basically these shouldn't exist on GenTreeIndir, they're misleading.

Copy link
Member Author

Choose a reason for hiding this comment

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

Good point, I can remove these.

@@ -3188,11 +3210,21 @@ GenTree* Compiler::optAssertionPropGlobal_RelOp(ASSERT_VALARG_TP assertions, Gen
{
op1->ChangeOperConst(GT_CNS_INT);
op1->AsIntCon()->gtIconVal = vnStore->ConstantValue<int>(vnCns);

if (vnStore->IsVNHandle(vnCns))
Copy link

Choose a reason for hiding this comment

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

Presumably this case happens only on 32 bit targets?

Copy link
Member Author

Choose a reason for hiding this comment

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

I was also considering not propagating handle constants into trees as they're generally not foldable and end up producing large immediates.

{
// A GT_TRUE is always the last node in a tree, so we can break here
assert((tree->gtNext == nullptr) && (stmt->GetNextStmt() == nullptr));
break;
Copy link

Choose a reason for hiding this comment

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

Hmm, can't remember exactly why I added this early exit for JTRUE nodes. Most likely for consistency with the assertion gen loop that has special handling for JTRUE. Here the only potentially unwanted side effect of not exiting seems to be setting the wrong bit in assertions. But since it's the last node of the block it doesn't matter...

@AndyAyersMS
Copy link
Member Author

@dotnet/jit-contrib anyone want to take a look?

Copy link

@briansull briansull 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, Left some comments

if (!tree->OperIs(GT_EQ, GT_NE))
{
return nullptr;
}

if (op1->gtOper != GT_LCL_VAR)
// Bail out if tree is not side effect free.
if ((tree->gtFlags & GTF_SIDE_EFFECT) != 0)

Choose a reason for hiding this comment

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

Can you describe the problem that you saw here when GTF_SIDE_EFFECT was true.
Did this change cause any current Asm diffs?

Copy link
Member Author

@AndyAyersMS AndyAyersMS Oct 30, 2019

Choose a reason for hiding this comment

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

No diffs from the previous version. I added this as a precaution, to parallel what we do above for the =/!= 0 case, since the simplification below will not preserve side effects.

src/jit/assertionprop.cpp Show resolved Hide resolved
Copy link

@briansull briansull left a comment

Choose a reason for hiding this comment

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

Handling of OAK_NOT_EQUAL for GT_IND not consistent with comments

*/
//------------------------------------------------------------------------
// optGlobalAssertionIsEqualOrNotEqual: Look for an assertion in the specified
// set that is one of op1 == op1, op1 != op2, *op1 == op2, *op1 != op2,

Choose a reason for hiding this comment

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

The code below only allows for *op1 == op2, not *op1 != op2

Copy link
Member Author

Choose a reason for hiding this comment

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

Thanks. Meant just to handle the equality case.


// Look for matching exact type assertions based on vtable accesses
if ((curAssertion->assertionKind == OAK_EQUAL) && (curAssertion->op1.kind == O1K_EXACT_TYPE) &&
op1->OperIs(GT_IND))

Choose a reason for hiding this comment

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

You don't allow OAK_NOT_EQUAL 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.

Right -- let me update the comment.

@AndyAyersMS AndyAyersMS merged commit 5216c8c into dotnet:master Nov 5, 2019
@AndyAyersMS AndyAyersMS deleted the AssertionPropRemoveRedundantExactTypeTest branch November 5, 2019 16:03
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
4 participants