Some gcc/clang compiler optimizations allow reordering the execution of code in the assembly (e.g. for gcc: -freorder-blocks -freorder-blocks-and-partition -freorder-functions). Is it safe to use such optimizations when de-/serializing data structures in a specific order?
For instance:
void write(int* data,std::ofstream& outstream)
{
outstream.write(reinterpret_cast<char*>(data),sizeof(int));
}
void read(int* data,std::ifstream& instream)
{
instream.read(reinterpret_cast<char*>(data),sizeof(int));
}
void serialize()
{
std::ofstream ofs("/somePath/to/some.file");
int i = 1;
int j = 2;
int k = 3;
write(i, ofs);
write(j, ofs);
write(k, ofs);
ofs.close();
}
void deserialize()
{
std::ifstream ifs("/somePath/to/some.file");
int i;
int j;
int k;
read(i, ifs);
read(j, ifs);
read(k, ifs);
ifs.close();
}
-freorder-blocks
, -freorder-blocks-and-partition
, and -freorder-functions
all influence the order in which code is laid out in your executable file:
-freorder-blocks
allows gcc to rearrange the straight-line blocks of assembly code that combine to form your function to try and minimize the number of branch prediction misses that your CPU might make.
-freorder-functions
takes the functions that the compiler deems unlikely to execute and moving them to a far away part of your executable file. The goal of doing so is to try and pack as much frequently-executed code into as little memory as possible so as to benefit from the instruction cache as much as possible.
-freorder-blocks-and-partition
is like -freorder-functions
, but at the assembly block level. If you have an if (unlikely(foo)) { x = 1; }
branch in your code, then the compiler might choose to take the code representing x = 1;
and move it away frequently executed code.
None of these will affect the control flow of your program. All optimizations will guarantee that if you write i
to a file and then j
to a file, then that will still be what is observed after optimizations are applied.