I'm writing a compiler that uses the time-honored strategy of using a C compiler as the back end, and I'm trying to figure out exactly how to handle integer sign.
I'm using machine word integers as the default (translating into
uintptr_t in the generated C), and while for myself I would prefer to make the default unsigned, I probably don't have much choice about making it signed just because that expectation is so widely ingrained.
I'm defining the result of integer overflow to be wraparound (at least by default, might add an option to throw an exception later), but in C, signed integer overflow is undefined behavior, so I can't just emit code that performs signed integer arithmetic. It seems to me there are two options:
Emit signed integers, but convert to unsigned for all arithmetic operations except division and right shift (these are the only ones where the difference matters, and also the only ones that can't overflow - edit: except for
INT_MIN/ -1; I had been considering that in the same category as division by zero, but of course it is strictly speaking an overflow).
Emit unsigned integers, but convert to signed for division (resisting the temptation to make division of negative numbers undefined behavior), right shift and comparison other than equality.
Emit signed integers anyway, use
-fwrapvwhen using GCC as the backend, and hope other C compilers either don't take advantage of signed overflow being undefined, or provide a switch to disable such optimizations.
Does the third option work (e.g. are there any C compilers where you can't make signed overflow wrap)? If not, which of the first two is likely to involve less code and opportunity for error? Is there anything I'm missing?