match: Simplify value-range guarded min/max expressions [PR125700] #214

Closed
sam-100 wants to merge 1 commit from sam-100/gcc:pr125700 into trunk
Member

The pattern:

    x == C ? y : min (x, y)

can be simplified to min (x, y) whenever C >= upper_bound (y),
because min (C, y) == y for all values y can take. Similarly:

    x == C ? y : max (x, y)

can be simplified to max (x, y) whenever C <= lower_bound (y).

Use ranger to query the value range of y and check the bound condition.

    PR tree-optimization/125700

gcc/ChangeLog:
PR tree-optimization/125700
* match.pd ((x == C) ? y : MIN/MAX (x, y)): New simplification.

gcc/testsuite/ChangeLog:

* gcc.dg/tree-ssa/pr125700.c: New test.
* gcc.dg/tree-ssa/pr125700-int-width.c: New test.
* gcc.dg/tree-ssa/pr125700-negative.c: New test.
* gcc.dg/tree-ssa/pr125700-range.c: New test.

Signed-off-by: Samarth Tandale samarth.tandale@oss.qualcomm.com

Testing:
Regression tested a cross compiler targeting AArch64 GNU/Linux on an
x86_64 GNU/Linux host, with execution tests run under QEMU; no
regressions found.

Changes since v1:

  • Extended the optimization beyond fixed type limits. It now handles constants
    when Ranger proves their relationship with y's value range and conservatively
    falls back when no useful range is available.
  • Added positive and negative test cases for Ranger-derived ranges.

CC: andrew.pinski@oss.qualcomm.com

The pattern: x == C ? y : min (x, y) can be simplified to min (x, y) whenever C >= upper_bound (y), because min (C, y) == y for all values y can take. Similarly: x == C ? y : max (x, y) can be simplified to max (x, y) whenever C <= lower_bound (y). Use ranger to query the value range of y and check the bound condition. PR tree-optimization/125700 gcc/ChangeLog: PR tree-optimization/125700 * match.pd ((x == C) ? y : MIN/MAX (x, y)): New simplification. gcc/testsuite/ChangeLog: * gcc.dg/tree-ssa/pr125700.c: New test. * gcc.dg/tree-ssa/pr125700-int-width.c: New test. * gcc.dg/tree-ssa/pr125700-negative.c: New test. * gcc.dg/tree-ssa/pr125700-range.c: New test. Signed-off-by: Samarth Tandale <samarth.tandale@oss.qualcomm.com> Testing: Regression tested a cross compiler targeting AArch64 GNU/Linux on an x86_64 GNU/Linux host, with execution tests run under QEMU; no regressions found. Changes since v1: - Extended the optimization beyond fixed type limits. It now handles constants when Ranger proves their relationship with y's value range and conservatively falls back when no useful range is available. - Added positive and negative test cases for Ranger-derived ranges. CC: andrew.pinski@oss.qualcomm.com
match: Simplify type-bound guarded min/max expressions [PR125700]
All checks were successful
/ format-checks (pull_request) Successful in 1m37s
4d042112a6
For MIN_EXPR, if x is TYPE_MAX_VALUE, then min (x, y) is y.
So:
	x == TYPE_MAX_VALUE ? y : min (x, y)
can be simplified to:
	min (x, y)

Similarly for MAX_EXPR, if x is TYPE_MIN_VALUE, then max (x, y)
is y.
So:
	x == TYPE_MIN_VALUE ? y : max (x, y)
can be simplified to:
	max (x, y)

This adds a combined match.pd pattern for MIN_EXPR and MAX_EXPR.

	PR tree-optimization/125700

gcc/ChangeLog:

	* match.pd: Fold type-bound guarded min/max expressions.

gcc/testsuite/ChangeLog:

	* gcc.dg/tree-ssa/pr125700.c: New test.
	* gcc.dg/tree-ssa/pr125700-int-width.c: New test.
	* gcc.dg/tree-ssa/pr125700-negative.c: New test.

Signed-off-by: Samarth Tandale <samarth.tandale@oss.qualcomm.com>
Member

Hi @sam-100. This bot helps send your PR as a patch series to the mailing list.

Next steps

  1. Write a clear PR description. It will be used as the cover letter.
  2. To CC extra people, add lines like this at the end of the PR description: CC: Reviewer1 <revi.ewer@example.com>, Reviewer2 <an.other@example.com>.
  3. To preview the emails, comment with /preview.
  4. When ready, request review in the Reviewers section. Or, if you just want to send the series, comment with /submit.
  5. Use the cover-letter links below to follow replies.
  6. For a new patch series, push your changes, update the PR description with a Changes since vX section, and comment with /submit again.

See Submitting Patches and UsingForge.

Consider joining the gcc and gcc-patches mailing lists..
For real time communication, check the gcc irc channels.

Or join #overseers on Libera Chat, particularly if this automation is not working (stay online to get replies, IRC does not save messages if people are not online).

<!-- pr-welcome --> Hi @sam-100. This bot helps send your PR as a patch series to the mailing list. ## Next steps 1. Write a clear PR description. It will be used as the cover letter. 2. To CC extra people, add lines like this **at the end** of the PR description: `CC: Reviewer1 <revi.ewer@example.com>, Reviewer2 <an.other@example.com>`. 3. To preview the emails, comment with `/preview`. 4. When ready, request review in the Reviewers section. Or, if you just want to send the series, comment with `/submit`. 5. Use the cover-letter links below to follow replies. 6. For a new patch series, push your changes, update the PR description with a `Changes since vX` section, and comment with `/submit` again. See [Submitting Patches](https://gcc.gnu.org/contribute.html#patches) and [UsingForge](https://gcc.gnu.org/wiki/UsingForge). Consider joining the [gcc and gcc-patches mailing lists.](https://gcc.gnu.org/lists.html). For real time communication, check the [gcc irc channels](https://gcc.gnu.org/wiki/GCConIRC). Or join [`#overseers`](https://web.libera.chat/#overseers) on Libera Chat, particularly if this automation is not working (stay online to get replies, IRC does not save messages if people are not online).
gcc/match.pd Outdated
@ -12710,0 +12719,4 @@
(with {
tree bound = (minmax == MIN_EXPR)
? TYPE_MAX_VALUE (type)
: TYPE_MIN_VALUE (type);
Member

I think we should use the ranger here.
Similar to minmax_from_comparison.
It should be something like

          int_range_max r;
          get_range_query (cfun)->range_of_expr (r, @0);
          if (r.undefined_p ())
            r.set_varying (TREE_TYPE (@0));
          widest_int value;
          if (minmax == MIN_EXPR)
            value = widest_int::from (r.upper_bound (),
                                                     TYPE_SIGN (TREE_TYPE (@0)));
          else
            value = widest_int::from (r.lower_bound (),
                                                     TYPE_SIGN (TREE_TYPE (@0)));

Then the if would be:
if (max == wi::to_widdest (@0))

I think we should use the ranger here. Similar to minmax_from_comparison. It should be something like ``` int_range_max r; get_range_query (cfun)->range_of_expr (r, @0); if (r.undefined_p ()) r.set_varying (TREE_TYPE (@0)); widest_int value; if (minmax == MIN_EXPR) value = widest_int::from (r.upper_bound (), TYPE_SIGN (TREE_TYPE (@0))); else value = widest_int::from (r.lower_bound (), TYPE_SIGN (TREE_TYPE (@0))); ``` Then the if would be: if (max == wi::to_widdest (@0))
Author
Member

I tried using the ranger as suggested. However, get_range_query (cfun)->range_of_expr (r, @0) does not to consider the conditional context in which @0 is being queried, so it does not provide the path-specific range established by the surrounding condition.

I also tried gimple_match_range_of_expr (r, @0, @0). However, the helper uses gimple_match_ctx (@0), which provides the definition statement of @0 as the context. In this case, that statement is outside the if (x <= 100) block, so the conditional range is still not considered.

Could you please verify whether this is the intended use of the ranger, or advise how to query the range of @0 using the current conditional context?

I tried using the ranger as suggested. However, get_range_query (cfun)->range_of_expr (r, @0) does not to consider the conditional context in which @0 is being queried, so it does not provide the path-specific range established by the surrounding condition. I also tried gimple_match_range_of_expr (r, @0, @0). However, the helper uses gimple_match_ctx (@0), which provides the definition statement of @0 as the context. In this case, that statement is outside the if (x <= 100) block, so the conditional range is still not considered. Could you please verify whether this is the intended use of the ranger, or advise how to query the range of @0 using the current conditional context?
Member

Version 1 of this pull request has been stored. It includes the following commits:

<!-- pr-new-version --> Version 1 of this pull request has been stored. It includes the following commits: - match: Simplify type-bound guarded min/max expressions [PR125700] - 4d042112a60614fdea9eface9d3b6c00fab7a260
sam-100 force-pushed pr125700 from 4d042112a6
All checks were successful
/ format-checks (pull_request) Successful in 1m37s
to 7e709962d4
All checks were successful
/ format-checks (pull_request) Successful in 1m18s
2026-09-19 07:42:54 +00:00
Compare
Author
Member

/preview

/preview
Member

Sent patch version 2 as a single email to @sam-100's email address.
Message ID is <bmm.hmfovtrc2o.gcc.gcc.sam-100.214.2.0@forge-stage.sourceware.org>.

Sent patch version 2 as a single email to @sam-100's email address. Message ID is `<bmm.hmfovtrc2o.gcc.gcc.sam-100.214.2.0@forge-stage.sourceware.org>`.
Author
Member

/submit

/submit
Member

Version 2 of this pull request has been stored. It includes the following commits:

<!-- pr-new-version --> Version 2 of this pull request has been stored. It includes the following commits: - match: Simplify value-range guarded min/max expressions [PR125700] - 7e709962d4f3c68b0f6f2522c743109a0d11aeea
Member

Pull Request versions:

# Base Head
1 19a304d368 4d042112a6 (diff)
2 7f405dfaa2 7e709962d4 (diff)

In order to compare , clone this repository and run

PR=214
git fetch origin "refs/versioned_pull/${PR}/*:refs/versioned_pull/${PR}/*"
PRV1=1
PRV2=2
git range-diff "refs/versioned_pull/${PR}/${PRV1}/base..refs/versioned_pull/${PR}/${PRV1}/head"  "refs/versioned_pull/${PR}/${PRV2}/base..refs/versioned_pull/${PR}/${PRV2}/head"
<!-- pr-versions --> Pull Request versions: | # | Base | Head | | | - | ---- | ---- | - | | 1 | 19a304d3680a1aeeb8ca412a6fe108a3f3b9d305 | 4d042112a60614fdea9eface9d3b6c00fab7a260 | [(diff)](https://forge.sourceware.org/gcc/gcc.git/compare/19a304d3680a1aeeb8ca412a6fe108a3f3b9d305...4d042112a60614fdea9eface9d3b6c00fab7a260) | | 2 | 7f405dfaa29e4c9d8c7b4e6ada13fa44ff053a0c | 7e709962d4f3c68b0f6f2522c743109a0d11aeea | [(diff)](https://forge.sourceware.org/gcc/gcc.git/compare/7f405dfaa29e4c9d8c7b4e6ada13fa44ff053a0c...7e709962d4f3c68b0f6f2522c743109a0d11aeea) | In order to compare , clone this repository and run ``` PR=214 git fetch origin "refs/versioned_pull/${PR}/*:refs/versioned_pull/${PR}/*" PRV1=1 PRV2=2 git range-diff "refs/versioned_pull/${PR}/${PRV1}/base..refs/versioned_pull/${PR}/${PRV1}/head" "refs/versioned_pull/${PR}/${PRV2}/base..refs/versioned_pull/${PR}/${PRV2}/head" ```
Member

Sent patch version 2 as a single email to gcc-patches mailing list gcc-patches@gcc.gnu.org and cc'd andrew.pinski@oss.qualcomm.com.
Cover letter

Sent patch version 2 as a single email to gcc-patches mailing list <gcc-patches@gcc.gnu.org> and cc'd andrew.pinski@oss.qualcomm.com. [Cover letter](https://inbox.sourceware.org/gcc-patches/bmm.hmfp34cu8w.gcc.gcc.sam-100.214.2.0@forge-stage.sourceware.org)
sam-100 changed title from match: Simplify type-bound guarded min/max expressions [PR125700] to match: Simplify range-bound guarded min/max expressions [PR125700] 2026-09-19 17:32:39 +00:00
sam-100 changed title from match: Simplify range-bound guarded min/max expressions [PR125700] to match: Simplify value-range guarded min/max expressions [PR125700] 2026-09-19 17:37:32 +00:00
sam-100 closed this pull request 2026-09-21 05:05:44 +00:00
All checks were successful
/ format-checks (pull_request) Successful in 1m18s

Pull request closed

Sign in to join this conversation.
No reviewers
No milestone
No assignees
3 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
gcc/gcc!214
No description provided.