Skip to content

Clean up null check handling in EffectAnalyzer#8422

Open
tlively wants to merge 6 commits intomainfrom
effects-null-ref-helpers
Open

Clean up null check handling in EffectAnalyzer#8422
tlively wants to merge 6 commits intomainfrom
effects-null-ref-helpers

Conversation

@tlively
Copy link
Member

@tlively tlively commented Mar 5, 2026

Each visitor previously handled implicit null checks of reference
operands in an ad hoc way. Different expressions had varying levels of
precision when reasoning about the null checks. For example, many would
just always set implicitTraps, while others would look at the
nullability of the operands to be more precise.

Factor the handling of null checks into a helper function and use it
everywhere applicable. This makes the code smaller, clearer, and more
precise. Update OptimizeCasts to add a new dummy operand to a dummy
expression because EffectAnalyzer will newly try to look at that
operand and it must not read uninitialized memory.

Some GUFA tests are updated to remove more side-effect-free expressions
now that EffectAnalyzer is more aggressive and can recognize them as
such.

Each visitor previously handled implicit null checks of reference
operands in an ad hoc way. Different expressions had varying levels of
precision when reasoning about the null checks. For example, many would
just always set `implicitTraps`, while others would look at the
nullability of the operands to be more precise.

Factor the handling of null checks into a helper function and use it
everywhere applicable. This makes the code smaller, clearer, and more
precise. Update OptimizeCasts to add a new dummy operand to a dummy
expression because EffectAnalyzer will newly try to look at that
operand and it must not read uninitialized memory.

Some GUFA tests are updated to remove more side-effect-free expressions
now that EffectAnalyzer is more aggressive and can recognize them as
such.
assert(!expr || expr->type.isRef());
if (expr && expr->type.isNull()) {
parent.trap = true;
return true;
Copy link
Member

Choose a reason for hiding this comment

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

IIUC, when we see a null, we mark it as trapping and tell the parent to stop computing effects. So e.g. a StructSet to a null would end up with the effects of { trap } when before this PR it had { trap, writes }.

We have several places where an analysis does .trap = false /* trapping is ok to ignore here, for reasons */ - after this PR, we would have no effects there at all. Is that still correct in those places?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, this should still be correct. The expression truly has no side effects other than to trap in such cases. Those passes must handle (unreachable) correctly, and this is no different.

Copy link
Member

Choose a reason for hiding this comment

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

ok, I am still slightly worried... but we do have a fuzzer 😄

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, I will fuzz this heavily before landing.

src/ir/effects.h Outdated

// Handle effects due to an explicit null check of the operands in `exprs`.
// Returns true iff there is no need to consider further effects.
bool handleNullChecked(std::initializer_list<Expression*> exprs) {
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
bool handleNullChecked(std::initializer_list<Expression*> exprs) {
bool handleTrapOnNull(std::initializer_list<Expression*> exprs) {

Perhaps this is clearer?

Copy link
Member

Choose a reason for hiding this comment

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

(since a "null check" is a more general term. also this is shorter)

Copy link
Member

Choose a reason for hiding this comment

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

Or just trapOnNull?

src/ir/effects.h Outdated
if (trapOnNull(curr->ref)) {
return;
}
// OOB acces to array.
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
// OOB acces to array.
// OOB access to array.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants