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

            Bug ID: 127244
           Summary: [x86-64] asm "=rm" output operand spilled through
                    stack slot unnecessarily when result is live across a
                    call
           Product: gcc
           Version: 16.2.1
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: rtl-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: ubizjak at gmail dot com
  Target Milestone: ---

Created attachment 65519
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=65519&action=edit
Minimized testcase

Compile the attachd testcase with -O2 for x86_64-linux-gnu (reduced from
native_save_fl()/x86_gsbase_read_cpu_inactive() in
arch/x86/include/asm/irqflags.h).

gcc -O2 -S produces:

  15:   9c                      pushf
  16:   8f 44 24 08             pop    0x8(%rsp)
  1a:   48 8b 5c 24 08          mov    0x8(%rsp),%rbx  <----- *** here ***
  1f:   fa                      cli
  20:   e8 00 00 00 00          call   25 <x86_gsbase_read_cpu_inactive+0x25>
                        21: R_X86_64_PLT32      __rdgsbase_inactive-0x4
  25:   80 e7 02                and    $0x2,%bh
  28:   74 01                   je     2b <x86_gsbase_read_cpu_inactive+0x2b>
  2a:   fb                      sti

i.e. the "=rm" output operand of the pushf/pop asm is satisfied via the memory
alternative, immediately followed by a reload of the same value into %rbx for
use across the call to __rdgsbase_inactive() and the later flags test/restore.
The store to 8(%rsp) is completely redundant.

Changing the constraint to "=r" gives the expected code:

  11:   9c                      pushf
  12:   5b                      pop    %rbx
  13:   fa                      cli
  14:   e8 00 00 00 00          call   19 <x86_gsbase_read_cpu_inactive+0x19>
                        15: R_X86_64_PLT32      __rdgsbase_inactive-0x4
  19:   80 e7 02                and    $0x2,%bh
  1c:   74 01                   je     1f <x86_gsbase_read_cpu_inactive+0x1f>
  1e:   fb                      sti

With "=rm", gcc should be able to make the same "r" choice it makes when the
constraint is forced to "=r", since a callee-saved hard reg is available and
cheaper than a spill + immediate reload.

This issue triggers some 40 - 50 times during default x86_64 config linux
kernel compile and results in assembly like:

   34220:       9c                      pushf
   34221:       8f 04 24                pop    (%rsp)
   34224:       48 8b 1c 24             mov    (%rsp),%rbx
   34228:       fa                      cli
   34229:       31 ff                   xor    %edi,%edi
   3422b:       be 00 00 02 00          mov    $0x20000,%esi
   34230:       e8 00 00 00 00          call   34235
<load_trampoline_pgtable+0x45>
                        34231: R_X86_64_PLT32   cr4_update_irqsoff-0x4
   34235:       80 e7 02                and    $0x2,%bh
   34238:       74 08                   je     34242
<load_trampoline_pgtable+0x52>
   3423a:       fb                      sti

and:

   35337:       9c                      pushf
   35338:       8f 04 24                pop    (%rsp)
   3533b:       4c 8b 34 24             mov    (%rsp),%r14
   3533f:       fa                      cli
   35340:       31 ff                   xor    %edi,%edi
   35342:       e8 00 00 00 00          call   35347 <do_arch_prctl_64+0x1e7>
                        35343: R_X86_64_PLT32   asm_load_gs_index-0x4
   35347:       41 f7 c6 00 02 00 00    test   $0x200,%r14d
   3534e:       4c 8b 44 24 08          mov    0x8(%rsp),%r8
   35353:       74 39                   je     3538e <do_arch_prctl_64+0x22e>
   35355:       fb                      sti

Reply via email to