Unnecessary instruction generated by GCC 7.2

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello,

Consider the following code:

#include <limits.h>

#if CHAR_BIT != 8
#error "Only octets (8-bit bytes) are supported"
#endif

static const char map[16] = "xyz";

void foo(unsigned char *src, char *buf)
{
	int hi = src[0] / 16;
	int lo = src[0] % 16;
	buf[0] = map[hi];
	buf[1] = map[lo];
}


$ gcc-7 -O2 -S -march=haswell -Wall -Wextra foo.c

foo:
	movzbl	(%rdi), %eax		# eax = src[0]
	movl	%eax, %edx		# edx = src[0]
	andl	$15, %eax		# eax = src[0] % 16 = lo
	shrb	$4, %dl			# edx = src[0] / 16 = hi
	movzbl	map(%rax), %eax		# eax = map[lo]
	andl	$15, %edx		# Unnecessary, see discussion below
	movzbl	map(%rdx), %edx
	movb	%al, 1(%rsi)
	movb	%dl, (%rsi)
	ret


Since CHAR_BIT is 8, it is guaranteed that 0 <= src[0] < 256
therefore 0 <= hi < 16
therefore "andl $15, %edx" is a no-op and could be removed.


In fact, if I change the program to:

#include <limits.h>

#if CHAR_BIT != 8
#error "Only octets (8-bit bytes) are supported"
#endif

static const char map[16] = "xyz";

void foo(unsigned char *src, char *buf)
{
	int hi = src[0] / 16;
	int lo = src[0] % 16;
	buf[0] = hi;
	buf[1] = map[lo];
}

Then the generated code is

foo:
	movzbl	(%rdi), %eax
	movl	%eax, %edx
	andl	$15, %eax
	movzbl	map(%rax), %eax
	shrb	$4, %dl
	movb	%dl, (%rsi)
	movb	%al, 1(%rsi)
	ret


In that case, GCC doesn't emit the unnecessary instruction.

Is this easily fixable? (FWIW, trunk on godbolt has the same behavior.)

Regards.



[Index of Archives]     [Linux C Programming]     [Linux Kernel]     [eCos]     [Fedora Development]     [Fedora Announce]     [Autoconf]     [The DWARVES Debugging Tools]     [Yosemite Campsites]     [Yosemite News]     [Linux GCC]

  Powered by Linux