Bug 89518 - missed optimisation for array address calculations
Summary: missed optimisation for array address calculations
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: tree-optimization (show other bugs)
Version: 8.3.0
: P3 normal
Target Milestone: ---
Assignee: Richard Biener
URL:
Keywords: missed-optimization
Depends on:
Blocks:
 
Reported: 2019-02-27 11:41 UTC by Arnaud Desitter
Modified: 2021-08-08 17:42 UTC (History)
0 users

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2019-02-27 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Arnaud Desitter 2019-02-27 11:41:08 UTC
Considering:

int f(int index, int stride) {
    const int i1 = index / stride;
    const int i2 = index % stride;
    const int index2 = i1*stride+i2;
    return index2; // expect: index2 = index
}

gcc 8.3 with "-O3" on x84_64 emits:
f(int, int):
        mov     eax, edi
        cdq
        idiv    esi
        imul    eax, esi
        add     eax, edx
        ret

By contrast, clang 7 with "-O3" emits
f(int, int):
        mov     eax, edi
        ret

MSVC 2017 with "/O2" emits:
int f(int,int)
        mov     eax, ecx
        ret     0

Is there a way to persuade gcc to simplify this expression at compile time?
Comment 1 Richard Biener 2019-02-27 11:54:44 UTC
We do not have a (a / b) * b + (a % b) simplification rule.  The following adds one:

Index: gcc/match.pd
===================================================================
--- gcc/match.pd        (revision 269242)
+++ gcc/match.pd        (working copy)
@@ -2729,6 +2729,13 @@ (define_operator_list COND_TERNARY
   (mult (convert1? (exact_div @0 @@1)) (convert2? @1))
   (convert @0))
 
+/* Simplify (A / B) * B + (A  % B) -> A.  */
+(for div (trunc_div ceil_div floor_div round_div)
+     mod (trunc_mod ceil_mod floor_mod round_mod)
+  (simplify
+   (plus:c (mult:c (div @0 @1) @1) (mod @0 @1))
+   @0))
+
 /* ((X /[ex] A) +- B) * A  -->  X +- A * B.  */
 (for op (plus minus)
  (simplify
Comment 2 Marc Glisse 2019-02-27 12:51:46 UTC
(In reply to Richard Biener from comment #1)
> We do not have a (a / b) * b + (a % b) simplification rule.

Indeed. That's surprising since we do have for trunc_div
/* X - (X / Y) * Y is the same as X % Y.  */
Comment 3 Richard Biener 2019-05-03 10:46:44 UTC
Author: rguenth
Date: Fri May  3 10:46:13 2019
New Revision: 270846

URL: https://gcc.gnu.org/viewcvs?rev=270846&root=gcc&view=rev
Log:
2019-05-03  Richard Biener  <rguenther@suse.de>

	PR middle-end/89518
	* match.pd: Add pattern to optimize (A / B) * B + (A % B) to A.

	* gcc.dg/pr89518.c: New testcase.

Added:
    trunk/gcc/testsuite/gcc.dg/pr89518.c
Modified:
    trunk/gcc/ChangeLog
    trunk/gcc/match.pd
    trunk/gcc/testsuite/ChangeLog
Comment 4 Richard Biener 2019-05-03 10:48:52 UTC
Fixed.