digitalmars.D.ldc - Optimizing away empty loop with step
- Vladimir Panteleev (26/26) Jul 30 2021 DMD [fails](https://issues.dlang.org/show_bug.cgi?id=22158) to
- David Nadlinger (7/10) Jul 30 2021 LLVM/Clang 10 didn't optimise it away for me with everything made
- Johan (5/15) Jul 31 2021 Adding that attribute to the function indeed works, but requires
- Iain Buclaw (12/31) Jul 30 2021 You can look at C-style IR dump using the GDC Tree/RTL output
- Iain Buclaw (15/47) Jul 30 2021 On digging around further, C *doesn't* optimize away this kind of
- Vladimir Panteleev (8/21) Jul 31 2021 I see, thanks for looking into it.
- Kagamin (1/1) Aug 02 2021 If step==0 the loop is infinite.
- Vladimir Panteleev (2/3) Aug 02 2021 Yes, but not iff.
DMD [fails](https://issues.dlang.org/show_bug.cgi?id=22158) to optimize away an empty for loop with an increment of 1. GDC and LDC both succeed. However, the results are more interesting if you make the step variable: ```d void fun(int a, int b, int step) { for (int i = a; i < b; i += step) { } } ``` The above code (valid C and D) compiles to an empty function with clang and gcc: https://godbolt.org/z/PnffvhecM However, all three D compilers fail to optimize away the loop: https://d.godbolt.org/z/r3MEGzoh1 Is the frontend doing something to prevent the loop from being optimized away as in C? My first guess was that the compiler refused to optimize it away because it couldn't prove that the loop will ever exit. But, the C compilers don't seem to have an issue with that. My second guess was that the C compilers were happy with optimizing it away because signed integer overflow is undefined in C. But, changing the type to unsigned didn't make a difference. https://godbolt.org/z/hMb83ne9d
Jul 30 2021
On 30 Jul 2021, at 10:58, Vladimir Panteleev via digitalmars-d-ldc wrote:My second guess was that the C compilers were happy with optimizing it away because signed integer overflow is undefined in C. But, changing the type to unsigned didn't make a difference.LLVM/Clang 10 didn't optimise it away for me with everything made unsigned. Clang trunk on Godbolt does, but that's because it makes use of the fact that infinite loops are UB in C (as encoded in the `mustprogress` function attribute). — David
Jul 30 2021
On Friday, 30 July 2021 at 10:09:55 UTC, David Nadlinger wrote:On 30 Jul 2021, at 10:58, Vladimir Panteleev via digitalmars-d-ldc wrote:Adding that attribute to the function indeed works, but requires LLVM 12: https://d.godbolt.org/z/1Yb7YnP7e -JohanMy second guess was that the C compilers were happy with optimizing it away because signed integer overflow is undefined in C. But, changing the type to unsigned didn't make a difference.LLVM/Clang 10 didn't optimise it away for me with everything made unsigned. Clang trunk on Godbolt does, but that's because it makes use of the fact that infinite loops are UB in C (as encoded in the `mustprogress` function attribute).
Jul 31 2021
On Friday, 30 July 2021 at 09:58:01 UTC, Vladimir Panteleev wrote:DMD [fails](https://issues.dlang.org/show_bug.cgi?id=22158) to optimize away an empty for loop with an increment of 1. GDC and LDC both succeed. However, the results are more interesting if you make the step variable: ```d void fun(int a, int b, int step) { for (int i = a; i < b; i += step) { } } ``` The above code (valid C and D) compiles to an empty function with clang and gcc: https://godbolt.org/z/PnffvhecM However, all three D compilers fail to optimize away the loop: https://d.godbolt.org/z/r3MEGzoh1 Is the frontend doing something to prevent the loop from being optimized away as in C?You can look at C-style IR dump using the GDC Tree/RTL output option. https://d.godbolt.org/z/eM8Pv91eT As you can see, the loop construct that GDC uses is treated as a `while (1) { }` statement. You can reproduce this in Clang by rewriting the for loop into a while loop. https://godbolt.org/z/hWePhqesq GCC is still unaffected, but looking at the generated code, they opt to instead implement both loops with labels and goto expressions.
Jul 30 2021
On Friday, 30 July 2021 at 10:21:37 UTC, Iain Buclaw wrote:On Friday, 30 July 2021 at 09:58:01 UTC, Vladimir Panteleev wrote:On digging around further, C *doesn't* optimize away this kind of loop. The actual compiler option that controls this is `-ffinite-loops`. ``` Assume that a loop with an exit will eventually take the exit and not loop indefinitely. This allows the compiler to remove loops that otherwise have no side-effects, not considering eventual endless looping as such. This option is enabled by default at -O2 for C++ with -std=c++11 or higher. ``` You can add this to the GDC compiler window to observe the optimization, or add `-fno-finite-loops` to the G++ compiler window for the inverse.DMD [fails](https://issues.dlang.org/show_bug.cgi?id=22158) to optimize away an empty for loop with an increment of 1. GDC and LDC both succeed. However, the results are more interesting if you make the step variable: ```d void fun(int a, int b, int step) { for (int i = a; i < b; i += step) { } } ``` The above code (valid C and D) compiles to an empty function with clang and gcc: https://godbolt.org/z/PnffvhecM However, all three D compilers fail to optimize away the loop: https://d.godbolt.org/z/r3MEGzoh1 Is the frontend doing something to prevent the loop from being optimized away as in C?GCC is still unaffected, but looking at the generated code, they opt to instead implement both loops with labels and goto expressions.
Jul 30 2021
On Friday, 30 July 2021 at 22:23:08 UTC, Iain Buclaw wrote:The actual compiler option that controls this is `-ffinite-loops`. ``` Assume that a loop with an exit will eventually take the exit and not loop indefinitely. This allows the compiler to remove loops that otherwise have no side-effects, not considering eventual endless looping as such. This option is enabled by default at -O2 for C++ with -std=c++11 or higher. ``` You can add this to the GDC compiler window to observe the optimization, or add `-fno-finite-loops` to the G++ compiler window for the inverse.I see, thanks for looking into it. I wonder if there's a way to tell the compiler (using portable D) that it can assume that the loop will not be infinite. moon-child on IRC pointed out that this loop can be infinite in many cases, e.g. if `b` is `uint.max` and for any even value of `step` (i.e. `i` cannot take any value that is `>= b`). (Maybe something like `__builtin_reachable` after the loop?)
Jul 31 2021
On Monday, 2 August 2021 at 11:09:26 UTC, Kagamin wrote:If step==0 the loop is infinite.Yes, but not iff.
Aug 02 2021