I am quite familiar with GCC -O3 flag, but how it differs from -Os, in which situation we should prefer one over other?
It depends. Do you need to optimize speed or size?
-O3
Optimize yet more. -O3 turns on all optimizations specified by -O2 and also turns on the -finline-functions, -funswitch-loops, -fpredictive-commoning, -fgcse-after-reload, -ftree-loop-vectorize, -ftree-slp-vectorize, -fvect-cost-model, -ftree-partial-pre and -fipa-cp-clone options.-O0
Reduce compilation time and make debugging produce the expected results. This is the default.-Os
Optimize for size. -Os enables all -O2 optimizations that do not typically increase code size. It also performs further optimizations designed to reduce code size.
-Os Disables the following optimization flags:
-falign-functions-falign-jumps-falign-loops-falign-labels-freorder-blocks-freorder-blocks-and-partition-fprefetch-loop-arrayshttp://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html
Actually, -O is a shorthand for a long list of independent optimizations. If you don't know what you need, just go for -O3.