GCC O2 'incorrectly' optimises my for loop
Posted: Fri Jun 14, 2024 10:13 am
Hello,
I've read the following thread: viewtopic.php?f=13&t=33499 and noted both the comments about 'a workman and his/her tools' and the need to provide a self-contained example. I've got a self-contained example (below) and I have also diagnosed the issue, but I still don't really understand why the optimisation is occurring as it does. I'd be interested in what other people may have to say about it.
Here are the methods to write a message to the debug port (in QEMU):
The kernel is calling it as follows:
When I compile it with I get the following output:
When I add the volatile keyword to the for loop, ie.
And re-compile and run, I get the following output:
I really don't understand why the volatile keyword is required, and without it, why the compiler is optimising out all but the first iteration of the for loop. Not understanding the reason is making me nervous about continuing to code with optimisations enabled, given it's changing the intention of my code (nb. I'm not blaming the tool, I'm acknowledging I don't understand the tool)
Furthermore, if I remove the volatile keyword and comment out the first loop branch:
The optimisation at O2 retains all the loops:
PS. The main repo is here and my (scrappy) exploratory code for the above on the following branch.
I've read the following thread: viewtopic.php?f=13&t=33499 and noted both the comments about 'a workman and his/her tools' and the need to provide a self-contained example. I've got a self-contained example (below) and I have also diagnosed the issue, but I still don't really understand why the optimisation is occurring as it does. I'd be interested in what other people may have to say about it.
Here are the methods to write a message to the debug port (in QEMU):
Code: Select all
void debug_writechar(char c)
{
__asm__ ("movb %0, %%al\n\t"
"outb %%al, $0xe9"
:
: "r" (c));
}
void debug(char* message)
{
for (int i = 0; message[i] != 0; i++)
{
if (i == 0)
{
debug_writechar(' ');
}
debug_writechar(message[i]);
}
}
Code: Select all
debug("Monkey lives here");
debug("Snail lives here");
Code: Select all
-ffreestanding -O2 -nostdlib -lgcc -Wall -Wextra -Werror -g -Wno-unused-parameter
Code: Select all
qemu-system-i386 -kernel kernel.bin -no-reboot -no-shutdown -debugcon stdio
M S
Code: Select all
for (volatile int i = 0; message[i] != 0; i++)
{
if (i == 0)
{
debug_writechar(' ');
}
debug_writechar(message[i]);
}
Code: Select all
qemu-system-i386 -kernel kernel.bin -no-reboot -no-shutdown -debugcon stdio
Monkey lives here Snail lives here
Furthermore, if I remove the volatile keyword and comment out the first loop branch:
Code: Select all
void debug(char* message)
{
for (int i = 0; message[i] != 0; i++)
{
/*if (i == 0)
{
debug_writechar(' ');
}*/
debug_writechar(message[i]);
}
}
Code: Select all
qemu-system-i386 -kernel kernel.bin -no-reboot -no-shutdown -debugcon stdio
Monkey lives hereSnail lives here
PS. The main repo is here and my (scrappy) exploratory code for the above on the following branch.