Q:

Optimization Disables Insertion of Address-Size Override Prefix

When compiling this:
#include <inttypes.h>

void foo(void)
{
        *(uint16_t *) (0xb8000) = 0xf61;
}

with
gcc test.c -c -m16 -O1

I get the following warning:
/tmp/ccyziKm4.s: Assembler messages:
/tmp/ccyziKm4.s:9: Warning: 753664 shortened to 32768

And when I drop the -O1 switch, I get none and gcc uses the 0x67 prefix to switch address size as expected (-m16 basically emits prefixed 32-bit code):
00000000 <foo>:
   0:   66 55                   push   %ebp
   2:   66 89 e5                mov    %esp,%ebp
   5:   66 b8 00 80 0b 00       mov    $0xb8000,%eax
   b:   67 c7 00 61 0f          movw   $0xf61,(%eax)
  10:   90                      nop
  11:   66 5d                   pop    %ebp
  13:   66 c3                   retl

So, obviously this has something to do with the optimization switch -O1.  The gcc man page describes all the options it sets and I wrote a script to single out every one of them and pass them to gcc, but it doesn't really work.  Now, gcc does not show the warning at all, even with the whole bunch of them. 
I appreciate any suggestions on how to resolve this. 

A:

I'd say that it is bug in gcc, but I see some logic behind this behavior:
GCC without optimization produces quite straightforward code with 2 instructions (I prefer intel syntax):
mov eax, 0xb8000 # move value 0xb8000 to eax
movw [eax], 0xf61 # move value 0xf61 to address stored in eax

Binary view:
66 b8 00 80 0b 00
   ^ operation: move 16 bit value to 16 register ax
^ size override prefix to indicate that 32 bit data is used instead of 16 bit, so eax should be used instead of ax

66 c7 00 61 0f
   ^ operation: move 16 bit value to 16 address in ax
^ size override prefix

GCC with optimization tries to optimize, so it generates following code:
movw [0xb8000], 0xf61 # mov value 0xf61 directly to 32 bit address 0xb8000 without any intermediate registers

Binary view:
66 c7 05 00 80 0b 00 61 0f
   ^ operation: move 16 bit value to 16 bit address
^ size override prefix

So, 32 bit op codes are actually the same opcodes as 16 bit, but with 66/67 prefix. 
And here is problem:

operation movw [REGISTER], 0xf61 is legal and officially supported in both 16/32 modes
operation movw [0xb8000], 0xf61 is legal, but values > 16 bit (0xffff) are not officially supported in 16 real mode, in 32 protected - they are officially supported

This is why compiler emits warning and truncates value 0xb8000 to 0x8000 to generate legal and officially supported instruction. 
Note: I believe that gcc should emit warning in first case too, as it does not work as you'd expected in 16 bit:

In real mode such instruction allowed, but eax cannot exceed 0xffff (effectively it does not use eax but only ax part). 
in protected/unreal mode such instruction allowed and full eax will be used. 

I don't know why gcc allows you to use m16 flag, while not supporting 16 bit code generation and real mode memory models properly.  I suggest you to switch to something else.  20 years ago watcom was very cool. 
If you're in unreal mode, it automatically means that you can and should use m32 instructions.