Unnecessary instruction generated by GCC 7.2

Mason slash.tmp@free.fr
Wed Nov 29 09:40:00 GMT 2017


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.



More information about the Gcc-help mailing list