This is the mail archive of the gcc-bugs@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug c/70604] New: switch statement optimization creates dead code


https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70604

            Bug ID: 70604
           Summary: switch statement optimization creates dead code
           Product: gcc
           Version: 6.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c
          Assignee: unassigned at gcc dot gnu.org
          Reporter: jpoimboe at redhat dot com
  Target Milestone: ---

Created attachment 38226
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=38226&action=edit
iscsi_target.i.gz

The linux kernel has a new tool named "objtool" which follows all possible code
paths for every .o file, looking for abnormalities.  In rare cases it has
stumbled on a gcc optimization issue related to switch statements, which leaves
some dead code (unreachable instructions) laying around, resulting in increased
code size and confusing assembler code.

Note: For some reason the likelihood of seeing this problem seems to have
diminished from gcc 5.3.1 to gcc 6.0.  We've seen the problem in three separate
object files in the kernel with gcc 5.3.1, but with gcc 6.0 there's only one
known occurrence of this issue.  Further, even in that one case, the size of
the dead code has decreased from several instructions in 5.3.1 to only a single
unreachable instruction in 6.0.

Here are the relevant assembler code excerpts, using gcc 6.0:

iscsit_handle_task_mgt_cmd:

[...snip...]

        jmp     *.L6212+64(%rip)        #
        .section        .rodata
        .align 8
        .align 4
.L6212:
        .quad   .L6211
        .quad   .L6070
        .quad   .L6214
        .quad   .L6214
        .quad   .L6214
        .quad   .L6214
        .quad   .L6082
        .quad   .L6089
        .quad   .L6096
        .text

[...snip...]

        jmp     .L6196  #
.L6211:
        movl    $8, %esi        #, _315
.L6213:
        movq    $.LC48, %rdi    #,


There's an indirect jump instruction in .text, along with a jump table in
.rodata, which is a common pattern for switch statements.  But this one's a
little different than the normal pattern: the indirect jump is hard-coded to
use a single entry in the jump table.  The other jump table entries are unused.
 Further, the code referenced in one of the entries (.L6211) is dead code and
completely unreachable from anywhere in the function.

Note that the -fsanitize=unreachable option is enabled, but this seems
unrelated: __builtin_unreachable() doesn't appear to have been used for this
code path, and the unreachable code block doesn't have a call to
__ubsan_handle_builtin_unreachable.

So to summarize, the issues are:

1) dead code in .text (in this case, the function only has one unreachable
instruction)

2) mostly unused (and completely unnecessary) jump table in .rodata

3) unnecessary indirect jump (a direct jump could be used instead)


$ gcc -v
Using built-in specs.
COLLECT_GCC=/usr/bin/gcc
COLLECT_LTO_WRAPPER=/usr/libexec/gcc/x86_64-redhat-linux/6.0.0/lto-wrapper
Target: x86_64-redhat-linux
Configured with: ../configure --enable-bootstrap
--enable-languages=c,c++,objc,obj-c++,fortran,ada,go,lto --prefix=/usr
--mandir=/usr/share/man --infodir=/usr/share/info
--with-bugurl=http://bugzilla.redhat.com/bugzilla --enable-shared
--enable-threads=posix --enable-checking=release --enable-multilib
--with-system-zlib --enable-__cxa_atexit --disable-libunwind-exceptions
--enable-gnu-unique-object --enable-linker-build-id
--with-linker-hash-style=gnu --enable-plugin --enable-initfini-array
--disable-libgcj --with-isl --enable-libmpx --enable-gnu-indirect-function
--with-tune=generic --with-arch_32=i686 --build=x86_64-redhat-linux
Thread model: posix
gcc version 6.0.0 20160311 (Red Hat 6.0.0-0.17) (GCC) 

$ gcc -Wp,-MD,drivers/target/iscsi/.iscsi_target.o.d  -nostdinc
-I./arch/x86/include -Iarch/x86/include/generated/uapi
-Iarch/x86/include/generated  -Iinclude -I./arch/x86/include/uapi
-Iarch/x86/include/generated/uapi -I./include/uapi -Iinclude/generated/uapi
-include ./include/linux/kconfig.h -D__KERNEL__ -Wall -Wundef
-Wstrict-prototypes -Wno-trigraphs -fno-strict-aliasing -fno-common
-Werror-implicit-function-declaration -Wno-format-security -std=gnu89 -mno-sse
-mno-mmx -mno-sse2 -mno-3dnow -mno-avx -m64 -falign-jumps=1 -falign-loops=1
-mno-80387 -mno-fp-ret-in-387 -mpreferred-stack-boundary=3 -mskip-rax-setup
-mtune=generic -mno-red-zone -mcmodel=kernel -funit-at-a-time
-maccumulate-outgoing-args -DCONFIG_AS_CFI=1 -DCONFIG_AS_CFI_SIGNAL_FRAME=1
-DCONFIG_AS_CFI_SECTIONS=1 -DCONFIG_AS_FXSAVEQ=1 -DCONFIG_AS_SSSE3=1
-DCONFIG_AS_CRC32=1 -DCONFIG_AS_AVX=1 -DCONFIG_AS_AVX2=1 -DCONFIG_AS_SHA1_NI=1
-DCONFIG_AS_SHA256_NI=1 -pipe -Wno-sign-compare -fno-asynchronous-unwind-tables
-fno-delete-null-pointer-checks -O2 --param=allow-store-data-races=0
-Wframe-larger-than=1024 -fno-stack-protector -Wno-unused-but-set-variable
-fomit-frame-pointer -fno-var-tracking-assignments
-Wdeclaration-after-statement -Wno-pointer-sign -fno-strict-overflow
-fconserve-stack -Werror=implicit-int -Werror=strict-prototypes
-Werror=date-time -Werror=incompatible-pointer-types -DCC_HAVE_ASM_GOTO   
-fsanitize=shift  -fsanitize=integer-divide-by-zero  -fsanitize=unreachable 
-fsanitize=vla-bound  -fsanitize=null  -fsanitize=signed-integer-overflow 
-fsanitize=bounds  -fsanitize=object-size  -fsanitize=returns-nonnull-attribute
 -fsanitize=bool  -fsanitize=enum  -fsanitize=alignment 
-Wno-maybe-uninitialized    -D"KBUILD_STR(s)=#s"
-D"KBUILD_BASENAME=KBUILD_STR(iscsi_target)" 
-D"KBUILD_MODNAME=KBUILD_STR(iscsi_target_mod)" -c -o
drivers/target/iscsi/iscsi_target.o drivers/target/iscsi/iscsi_target.c

This is with upstream Linux tag v4.6-rc2.  I've attached a gzipped version of
the .i file and will also attach the Linux .config file.

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]