5

On ARM Cortex-M3, for example, CLZ instruction is present, it counts leading zeros of an 32 bit integer. If integer is zero, result is 32.

In gcc, on the other hand, I can use a __builtin_clz function. However, according to gcc documentation:

Built-in Function: int __builtin_clz (unsigned int x).
Returns the number of leading 0-bits in x, starting at the most significant bit position. If x is 0, the result is undefined.

So if using this builtin I should manually handle zero? Or is it guaranted to be compiled to CLZ instruction if such an instruction is present on target machine?

Quotes from gcc documentation are highly appritiated!

Amomum
  • 6,217
  • 8
  • 34
  • 62
  • 4
    Not sure if dupe, but at least relevant: [How undefined are __builtin_ctz(0) or __builtin_clz(0)?](https://stackoverflow.com/q/19527897/694733). – user694733 Nov 07 '18 at 12:08
  • Hmmm ... fix syntax and use `asm "clz";`? – pmg Nov 07 '18 at 12:53
  • 1
    @pmg i'm afraid that using inline assembly tends to worsen compilers ability to optimize code. I might be wrong though. – Amomum Nov 07 '18 at 12:55

1 Answers1

7

The builtins provide the functions described for them. They are not guaranteed to compile to specific instructions.

Note that the GCC documentation says these are functions: “GCC provides a large number of built-in functions.” It does not tell you they generate specific instructions. For __builtin_clz, it says “Returns the number of leading 0-bits in x, starting at the most significant bit position. If x is 0, the result is undefined.” The documentation here simply means what it says: __builtin_clz is a function that returns the number of leading 0-bits in x, starting at the most significant bit position, and, if x is 0, the result is undefined. There is no statement in the documentation that __builtin_clz provides a count-leading-zeros instruction, so you cannot expect that it provides a count-leading-zeros instruction.

The compiler is free to implement builtins in any way that provides the specified functions. Since the specified function has undefined behavior for zero, you cannot expect the compiler will provide your desired behavior for zero, via a clz instruction or otherwise.

We can expect that optimization will generally use the obvious instructions when suitable. But the compiler may also combine the builtin functions with other code (possibly resulting in a code sequence in which the usual instruction is not needed or another instruction is better), evaluate constant expressions at compile-time, and make other non-obvious optimizations. Consider that, if the compiler recognizes a code path in which the argument to __builtin_clz is zero, it may replace that code path with anything, including deleting it entirely, since its behavior is undefined.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
  • Presumably you mean "you can *not* expect the compiler will provide your desired behavior" at the end of the 1st paragraph? – cooperised Nov 07 '18 at 12:49
  • Your answer does make sense but is that "They are not guaranteed to compile to specific instructions." some kind of 'common knowledge' or it is explicitly said in the docs somewhere? – Amomum Nov 07 '18 at 12:53
  • @Amomum: The GCC documentation specifies them as functions, not as instructions. See my new second paragraph. – Eric Postpischil Nov 07 '18 at 12:57
  • 2
    @Amomum, this is in the realm of "why would you expect otherwise?" Just as Eric says, the documentation specifies these as *functions*. What the compiler actually does with them is an implementation detail. It is not safe or reasonable to assume anything more or different about them than the documentation says. – John Bollinger Nov 07 '18 at 12:59
  • Fair enough. Thanks! – Amomum Nov 07 '18 at 13:08