If you read this expecting a compiler bug then prepare to be disappointed! This is just an “I didn’t know the compiler did that” observation that I stumbled across today whilst handling an oops report. I thought it was interesting.
So…
If we hand the following C to the GNU C compiler (including the RISCstar toolchain) then it will generate breakpoint instructions (or “undefined” instructions on x86-64):
int f(int x, int y) {
return x / (y ? __builtin_clz(y) : 0);
}
The ternary would normally be an inline function but has been fully expanded in the example above. It has been defensively coded to avoid calling __builtin_clz(0) (which is undefined). Sadly in our case the output is used as a divisor meaning that, although the ternary has a defined value, there is still a divide-by-zero if y is zero… and that is also undefined.
Compilers can do pretty much anything when there is undefined behaviour (including removing the zero check entirely) but gcc’s behaviour is interesting. It recognises there is no point in generating any real code to implement behaviour that is known to be undefined so it generates a breakpoint instead!
f:
beq a1,zero,.L7 # Branch to .L7 if argument 1 is zero
clzw a1,a1 # Count Leading Zeros in Word
divw a0,a0,a1 # Divide Word
ret
.L7:
ebreak # Breakpoint
Doing a little archaeology led me to discover that gcc has been doing this since gcc 7.1 was released in 2017. However I’ve never seen it before. Perhaps I just don’t write enough undefined behavior bugs!
Anyhow, if you actually do find this is interesting, this is the Compiler Explorer sandpit I used to examine things a little more: