0

Consider the following code:

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

class chartolower {
private:
    char s[50000];
public:
    void populates(int index, int val) { s[index] = val; }
    size_t strlen(const char *s) const {
        long length = 0;
        while (*s != '\0') {
            s++;
            length++;
        }
        return length;
    }
    /*Convert string to lower case: slow*/
    void lower1() {
        long i;
        for (i = 0; i < strlen(s); i++)
            if (s[i] >= 'A' && s[i] <= 'Z')
                s[i] -= ('A' - 'a');           //Case(1) strlen(s) not optimized away
                //i = i;                       //Case(2) strlen(s) optimized away
                //if(s[i] != '\0') s[i] = s[i];//Case(3) strlen(s) not optimized away
                //s[i] = s[i];                 //Case(4) strlen(s) not optimized away
    }
};

int main() {
        chartolower s;

        for (int i = 0; i < 49999; i++)
            s.populates(i, 65);//ASCII for A
        s.populates(49999, '\0');
        clock_t start_t, end_t, total_t;
        start_t = clock();
        s.lower1();
        end_t = clock();
        total_t = (end_t - start_t);
        printf("Total time taken by CPU Lower 1: %d\n", total_t);

        getchar();
}

On my computer, (Visual Studio 2017, Release Mode Build) the output of the 4 cases are:

Case(1) Total time taken by CPU Lower 1: 3477
Case(2) Total time taken by CPU Lower 1: 0
Case(3) Total time taken by CPU Lower 1: 3445
Case(4) Total time taken by CPU Lower 1: 3455

Case(1), I can understand why strlen(s) of the line for (i = 0; i < strlen(s); i++) is not optimized away since s[i] can be changed. Case(2), it is optimized away since s[i] for all i remains unchanged. Case(3) it is not clear to me why the compiler is unable to optimize strlen(s) away. I would have expected the compiler to figure out that strlen(s) should compute until it encounters a \0 and this is precisely the condition that is checked in Case(3). Case(4) also does not optimize away and I would have thought that it should be optimized away since it is similar to Case(2).

What causes the optimizations in Case(2) but not the other cases?

Tryer
  • 3,580
  • 1
  • 26
  • 49
  • It is pretty obvious that `i = i` in Case 2 does nothing, since `i` is a local variable and code outside the function cannot change it. The compiler can then reason that the body of the loop does nothing, and then optimise out the whole loop - including the calls of `strlen()`. Case 1 obviously can't be optimised out, since it changes `s[i]`. In cases 3 and 4, `s` is defined in another scope, so can potentially be changed by other code - including your `strlen()`, which the optimiser is not required to analyse to determine if the loop does nothing. A `const` function CAN have side effects. – Peter Sep 23 '18 at 04:27
  • 1
    @Peter Reg case4, `s[i] = s[i];` does not change to `s`. `strlen()` is also guaranteed not to cause any change in the object. While I understand that a `const` function can have side effects, it is not clear to me why the compiler is unable to deduce that there is no side effect in this case. So, it appears that this is a missed optimization. – Tryer Sep 23 '18 at 04:37
  • 1
    It's a missed optimization since GCC is able to optimize it under `-O2`. – xskxzr Sep 23 '18 at 04:40
  • BTW, please [don't use `%d` to print a value of `clock_t`](https://stackoverflow.com/questions/1083142/what-s-the-correct-way-to-use-printf-to-print-a-clock-t). It may result in UB. – xskxzr Sep 23 '18 at 04:42
  • Case 4: it depends on how aggressive the optimiser is. While YOU can say `strlen()` has no side effects, the compiler is not required to assume that nor perform analysis to check if it is true. Optimisers are complicated sections of code, and there is often a trade-off between compilation times (which developers vocally demand be short) and the number of optimisation opportunities that actually get analysed. Practically, cases that seem simple to you can be quite complicated for a compiler, and vendors are disinclined to implement more complicated analysis (by default). – Peter Sep 23 '18 at 04:55

0 Answers0