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

Forbid creation of non-faulting null-check nodes. #77078

Merged
merged 12 commits into from
Jan 28, 2023

Conversation

JulieLeeMSFT
Copy link
Member

@JulieLeeMSFT JulieLeeMSFT commented Oct 15, 2022

Fixes #44227.

There are 2 methods that create GT_NULLCHECK: gtNewNullCheck and gtChangeOperToNullCheck.

Edit: To delete an unnecessary node, we replaced the node with a GT_NULLCHECK or GT_NOP and allowed later phases to delete it.

@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 Oct 15, 2022
@ghost ghost assigned JulieLeeMSFT Oct 15, 2022
@ghost
Copy link

ghost commented Oct 15, 2022

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

Issue Details

Draft to test #44227.

Author: JulieLeeMSFT
Assignees: -
Labels:

area-CodeGen-coreclr

Milestone: -

@JulieLeeMSFT JulieLeeMSFT marked this pull request as draft October 15, 2022 14:29
@JulieLeeMSFT JulieLeeMSFT added this to the 8.0.0 milestone Oct 15, 2022
@JulieLeeMSFT
Copy link
Member Author

Fixed all asserts, but there are size and throughput regressions on Arm64. Link

@AndyAyersMS @kunalspathak PTAL.

@JulieLeeMSFT JulieLeeMSFT marked this pull request as ready for review October 27, 2022 03:28
const bool isContainable = false;
if (ind->Addr() != nullptr)
{
const bool isContainable = IsSafeToContainMem(ind, ind->Addr());
Copy link
Member

Choose a reason for hiding this comment

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

This is hiding the other isContainable and then going out of scope and the value is lost.

Copy link
Member

Choose a reason for hiding this comment

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

Yep and this is the reason for so many diffs.

Copy link
Member Author

Choose a reason for hiding this comment

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

oh I forgot to remove it when moving it out of if. Thanks for spotting it.

Copy link
Member

Choose a reason for hiding this comment

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

just a nit here - you could write it as

const bool isContainable = (ind->Addr() != nullptr) && IsSafeToContainMem(ind, ind->Addr());

if you wanted to preserve the constness or shorten it. I don't think it's a big deal.

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 for the code snippet. Will make that change.

@BruceForstall BruceForstall marked this pull request as draft November 28, 2022 20:06
@BruceForstall
Copy link
Member

@JulieLeeMSFT This was stale; I converted to Draft. Please convert back to non-Draft when it's ready for final code reviews.

@ghost ghost closed this Dec 28, 2022
@ghost
Copy link

ghost commented Dec 28, 2022

Draft Pull Request was automatically closed for 30 days of inactivity. Please let us know if you'd like to reopen it.

@JulieLeeMSFT JulieLeeMSFT reopened this Dec 29, 2022
@JulieLeeMSFT JulieLeeMSFT marked this pull request as ready for review December 29, 2022 04:00
@JulieLeeMSFT
Copy link
Member Author

Diff result:

  • Small (~130 Bytes) code size improvements.
  • Minor throughput diff (0.01%) as shown in the second screenshot below.

image

image

@JulieLeeMSFT
Copy link
Member Author

@dotnet/jit-contrib @BruceForstall, it is ready to review.
Failure is a knonw issue: #75244.

src/coreclr/jit/compiler.cpp Outdated Show resolved Hide resolved
src/coreclr/jit/compiler.cpp Outdated Show resolved Hide resolved
src/coreclr/jit/compiler.cpp Outdated Show resolved Hide resolved
src/coreclr/jit/gentree.cpp Outdated Show resolved Hide resolved
src/coreclr/jit/gentree.cpp Outdated Show resolved Hide resolved
src/coreclr/jit/importer.cpp Outdated Show resolved Hide resolved
@@ -8251,7 +8251,14 @@ void Compiler::impImportBlockCode(BasicBlock* block)
// via an underlying address, just null check the address.
if (op1->OperIs(GT_FIELD, GT_IND, GT_OBJ))
{
gtChangeOperToNullCheck(op1, block);
if (fgAddrCouldBeNull(op1->AsUnOp()->gtGetOp1()))
Copy link
Member

Choose a reason for hiding this comment

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

The op1 (addr) of a static GT_FIELD can be nullptr, but fgAddrCouldBeNull doesn't check for that. Could we AV 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.

As you said, if the op1 address of GT_FIELD can be nullptr, we want true returned from fgAddrCouldBeNull(op1->gtGetOp1()). And, it falls through to the default case and returns true. Isn't it enough?

Copy link
Member

Choose a reason for hiding this comment

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

No, because fgAddrColdBeNull() has switch (addr->OperGet()) and in the case I'm worried about, addr will be nullptr, so that would AV. Now, maybe there's some reason the case I'm worried about doesn't happen.

Or, maybe you can rewrite it to protect against that, e.g.:

                                const GenTree* addr = op1->gtGetOp1();
                                if ((addr != nullptr) && fgAddrCouldBeNull(addr))
                                {
                                    gtChangeOperToNullCheck(op1, block);
                                }
                                else
                                {
                                    op1 = gtNewNothingNode();
                                }

(presumably static fields don't need null checks)

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.

src/coreclr/jit/lower.cpp Show resolved Hide resolved
src/coreclr/jit/lower.cpp Show resolved Hide resolved
src/coreclr/jit/lower.cpp Outdated Show resolved Hide resolved
@ghost ghost added the needs-author-action An issue or pull request that requires more info or actions from the author. label Jan 5, 2023
@ghost ghost added the no-recent-activity label Jan 20, 2023
@ghost
Copy link

ghost commented Jan 20, 2023

This pull request has been automatically marked no-recent-activity because it has not had any activity for 14 days. It will be closed if no further activity occurs within 14 more days. Any new comment (by anyone, not necessarily the author) will remove no-recent-activity.

@ghost ghost removed no-recent-activity needs-author-action An issue or pull request that requires more info or actions from the author. labels Jan 21, 2023
@JulieLeeMSFT
Copy link
Member Author

@BruceForstall, it is ready to review.

else
{
JITDUMP("Replace an unused OBJ/BLK node [%06d] with a NOTHING node\n", dspTreeID(node));
node = m_compiler->gtNewNothingNode();
Copy link
Member

Choose a reason for hiding this comment

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

The problem is that Append(node) here happens before you set node = m_compiler->gtNewNothingNode();. The NothingNode gets created then never used. And for the non-faulting case, the original BLK node is still on the side-effect list.

I think you want code more like this:

                if (m_compiler->gtNodeHasSideEffects(node, m_flags))
                {
                    if (node->OperIsBlk() && !node->OperIsStoreBlk())
                    {
                        // Check for a guaranteed non-faulting IND, and create a NOP node instead of a NULLCHECK in that case.
                        if (m_compiler->fgAddrCouldBeNull(node->AsBlk()->Addr()))
                        {
                            Append(node);
                            JITDUMP("Replace an unused OBJ/BLK node [%06d] with a NULLCHECK\n", dspTreeID(node));
                            m_compiler->gtChangeOperToNullCheck(node, m_compiler->compCurBB);
                        }
                        else
                        {
                            JITDUMP("Dropping non-faulting OBJ/BLK node [%06d]\n", dspTreeID(node));
                        }
                    }
                    else
                    {
                        Append(node);
                    }
                    return Compiler::WALK_SKIP_SUBTREES;
                }

@@ -8251,7 +8251,14 @@ void Compiler::impImportBlockCode(BasicBlock* block)
// via an underlying address, just null check the address.
if (op1->OperIs(GT_FIELD, GT_IND, GT_OBJ))
{
gtChangeOperToNullCheck(op1, block);
if (fgAddrCouldBeNull(op1->AsUnOp()->gtGetOp1()))
Copy link
Member

Choose a reason for hiding this comment

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

No, because fgAddrColdBeNull() has switch (addr->OperGet()) and in the case I'm worried about, addr will be nullptr, so that would AV. Now, maybe there's some reason the case I'm worried about doesn't happen.

Or, maybe you can rewrite it to protect against that, e.g.:

                                const GenTree* addr = op1->gtGetOp1();
                                if ((addr != nullptr) && fgAddrCouldBeNull(addr))
                                {
                                    gtChangeOperToNullCheck(op1, block);
                                }
                                else
                                {
                                    op1 = gtNewNothingNode();
                                }

(presumably static fields don't need null checks)

@ghost ghost added the needs-author-action An issue or pull request that requires more info or actions from the author. label Jan 25, 2023
@ghost ghost removed the needs-author-action An issue or pull request that requires more info or actions from the author. label Jan 26, 2023
@JulieLeeMSFT
Copy link
Member Author

@BruceForstall, it is ready to review.

image

image

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.

Forbid creation of non-faulting null-check nodes.
4 participants