1

Disclaimer, this is about shift overflows which I know gives undefined behavior; so this really shouldn't be a question. The reason I am asking this is for my curiosity.

Here is my code.

test.c:

#include <stdio.h>

void func(int val)
{
    int allOnes = 0xffffffff;

    printf("0x%x << 32  = 0x%x\n", allOnes, allOnes << 32);
    printf("0x%x << val = 0x%x\n", allOnes, allOnes << val);
}

int main()
{
    func(32);
}

When I run this with no compiler optimizations (gcc -O0 -Wall -g test.c -o test.o) I get the following.

0xffffffff << 32  = 0xffffffff
0xffffffff << val = 0xffffffff

However, when I run this with compiler optimizations (gcc -O1 -Wall -g test.c -o test.o) I get the following.

0xffffffff << 32  = 0x0
0xffffffff << val = 0xffffffff

My question is: what causes this?

EDIT: More specifically, why is there a discrepancy between running with compiler optimization and without?

Zack Jorquera
  • 554
  • 7
  • 13
  • @AnttiHaapala: This is not a duplicate of those questions. Those questions ask what the language standards say about shifting by the word length (or more), or why. This question specifically asks about compiler behavior, not language specification. – Eric Postpischil Jan 12 '20 at 20:04
  • @EricPostpischil of course it is a duplicate of those. Behaviour is undefined. And one of the answers even detailed exactly why this is behaviour happens on x86, including that shl does mod 32 – Antti Haapala -- Слава Україні Jan 12 '20 at 21:28
  • @EricPostpischil notice that the new duplicate notice says that "a community member has associated this with a similar post", it does not claim that the question is a duplicate. – Antti Haapala -- Слава Україні Jan 12 '20 at 21:30
  • @AnttiHaapala: The only effect of the C standard saying something is “undefined” in its meaning of that word is that the C standard imposes no requirements on the behavior. It does not nullify anything else that affects the program—not the behavior of the compiler, not the workings of the operating system, not the specification of the hardware, nothing. There are useful things to learn in asking how and why the compiler does something, even if that behavior is not defined by a language standard. E.g., here the compiler evaluates an expression at compile-time, which is a useful thing to learn. – Eric Postpischil Jan 12 '20 at 22:08
  • @AnttiHaapala: Even if it were not useful, it is nonetheless a **different** thing to ask about that those other questions do not, and this is therefore not a duplicate question and is not answered by the answers to those other questions. – Eric Postpischil Jan 12 '20 at 22:09
  • @EricPostpischil [this answer](https://stackoverflow.com/a/33058550/918959) does answer the question . You can always add another answer to that question , there's no sense in having two separate questions with slightly different wording and common answers . The link message says in bold, "This question already has answers here:" which is patently true – M.M Jan 12 '20 at 22:33
  • @M.M: No, that answer does not answer this question. That answer explains why a particular result is obtained when `-O0` is used: The compiler issues a shift instruction, and the shift instruction uses only five bits of a shift value, and the result is no shift. It does not explain why the behavior differs when `-O1` is used. – Eric Postpischil Jan 12 '20 at 23:20
  • @EricPostpischil: What did the authors of the Standard say about how they expected commonplace implementations to process `unsigned mul_mod_65536(unsigned short x, unsigned short y) { return (x*y) & 0xFFFFu;}` in cases where `x` exceeds `INT_MAX/y`? Does gcc consistently behave that way? While the authors of the Standard didn't intend that for them to categorize an action as UB would nullify everything else, the authors of gcc treat such categorizations that way anyhow. – supercat Jan 15 '20 at 23:30

1 Answers1

2

I did some digging and I found when you use compiler optimizations (-O1), the compiler replaces the shift operation with its "result". In the assembly, there is a mov edx, 0 as opposed to a shl edx, 32.

The discrepancy here is just due to the processor and the compiler having different results. It is undefined behavior after all.

Zack Jorquera
  • 554
  • 7
  • 13