Can I get rid of the sign extension between CTZ and adding a pointer?

For code such as:

#include <stdint.h>

char* ptrAdd(char* ptr, uint32_t x)
{
    return ptr + (uint32_t)__builtin_ctz(x);
}

GCC generates a character extension: ( link godbolt )

xor eax, eax
rep bsf eax, esi
cdqe ; sign-extend eax into rax
add rax, rdi
ret

This, of course, is completely redundant - it is a blatant expression meaning an unsigned integer. Can I convince the GCC not to do this?

The problem exists with GCC 4.9.0, but before that it was an explicit null extension, which is also redundant.

+4
source share
1 answer

A particular solution is to use the 64-bit version ctzalong with the argument -march, so instead it is bsfused tzcnt, for example:

char* ptrAdd(char* ptr, uint32_t x)
{
    return ptr + __builtin_ctzl(x);
}

This results in unsigned expansion:

ptrAdd(char*, unsigned int):
  mov eax, esi
  tzcnt rax, rax
  add rax, rdi
  ret

mov ( 32 64 ), xor 32- ( , tzcnt ). , mov . 64- tzcnt 32-, , undefined ( gcc, tzcnt).

, -march, tzcnt, bsf, .

, bsf tzcnt , bsf undefined . , , 0 63, . , int, "" (__builtin_clzl (x) & 0xff) == 0xdeadbeef.

gcc docs __builtin_ctzl "undefined" - , , C/++ "undefined", - ( ), " ".

gcc bugzilla, 7 .

+4

Source: https://habr.com/ru/post/1693220/


All Articles