Quuxplusone / LLVMBugzillaTest

0 stars 0 forks source link

Bad machine code: Instruction loads from dead spill slot #38127

Open Quuxplusone opened 6 years ago

Quuxplusone commented 6 years ago
Bugzilla Link PR39154
Status NEW
Importance P enhancement
Reported by bjorn.a.pettersson@ericsson.com
Reported on 2018-10-02 08:27:46 -0700
Last modified on 2018-10-02 08:27:46 -0700
Version trunk
Hardware PC Linux
CC llvm-bugs@lists.llvm.org
Fixed by commit(s)
Attachments remat-undef-use.mir (1199 bytes, text/plain)
Blocks
Blocked by
See also
Created attachment 20951
reduced reproducer

Running the attached reproducer gives:

llc  -run-pass greedy -verify-regalloc -mtriple x86_64-- -o - remat-undef-
use.mir

********** MACHINEINSTRS **********
# Machine code for function test: IsSSA, NoPHIs, TracksLiveness
Frame Objects:
  fi#-1: size=1504, align=8, fixed, at location [SP+8]
  fi#0: size=4, align=4, at location [SP+8]

0B      bb.0:
          successors: %bb.1(0x80000000); %bb.1(100.00%)

16B       dead %3:gr32 = MOV32rm $rsp, 1, $noreg, 8, $noreg :: (load 4 from
%fixed-stack.0, align 16)
32B       %1:gr32 = MOV32rm %stack.0, 1, $noreg, 0, $noreg :: (load 4 from
%stack.0)

48B     bb.1:
        ; predecessors: %bb.0, %bb.1
          successors: %bb.1(0x80000000); %bb.1(100.00%)

56B       %2:gr32 = MOV32rm $rsp, 1, $noreg, 8, $noreg :: (load 4 from %fixed-
stack.0, align 16)
64B       INLINEASM &nop [sideeffect] [attdialect],
$0:[regdef:GR32_ABCD_and_GR32_BSI], implicit %2:gr32
80B       INLINEASM &nop [sideeffect] [attdialect], $0:[clobber], implicit-def
dead early-clobber $rax, $1:[clobber], implicit-def dead early-clobber $rbx,
$2:[clobber], implicit-def dead early-clobber $rcx, $3:[clobber], implicit-def
dead early-clobber $rdx, $4:[clobber], implicit-def dead early-clobber $rsi,
$5:[clobber], implicit-def dead early-clobber $rdi, $6:[clobber], implicit-def
dead early-clobber $rbp, $7:[clobber], implicit-def dead early-clobber $r8,
$8:[clobber], implicit-def dead early-clobber $r9, $9:[clobber], implicit-def
dead early-clobber $r10, $10:[clobber], implicit-def dead early-clobber $r11,
$11:[clobber], implicit-def dead early-clobber $r12, $12:[clobber], implicit-
def dead early-clobber $r13, $13:[clobber], implicit-def dead early-clobber
$r14, $14:[clobber], implicit-def dead early-clobber $r15
96B       JMP_1 %bb.1

# End machine code for function test.

*** Bad machine code: Instruction loads from dead spill slot ***
- function:    test
- basic block: %bb.0  (0x4514ef8) [0B;48B)
- instruction: 32B      %1:gr32 = MOV32rm %stack.0, 1, $noreg, 0, $noreg ::
(load 4 from %stack.0)
- operand 1:   %stack.0
Live stack: SS#0 EMPTY  0@x weight:0.000000e+00

*** Bad machine code: Instruction ending live segment on dead slot has no dead
flag ***
- function:    test
- basic block: %bb.0  (0x4514ef8) [0B;48B)
- instruction: 32B      %1:gr32 = MOV32rm %stack.0, 1, $noreg, 0, $noreg ::
(load 4 from %stack.0)
- liverange:   [32r,32d:0)  0@32r
- v. register: %1
- segment:     [32r,32d:0)
LLVM ERROR: Found 2 machine code errors.

The problem with "Instruction ending live segment on dead slot has no dead
flag" might be a duplicate of https://bugs.llvm.org/show_bug.cgi?id=33024

Running with -debug we can see this:

Inline spilling GR32:%0 [16r,112B:0)  0@16r weight:4.188229e+00
From original %0
        remat:  56r     %2:gr32 = MOV32rm $rsp, 1, $noreg, 8, $noreg :: (load 4 from %fixed-stack.0, align 16)
                64e     INLINEASM &nop [sideeffect] [attdialect], $0:[regdef:GR32_ABCD_and_GR32_BSI], implicit killed %2:gr32

All defs dead: dead %0:gr32 = MOV32rm $rsp, 1, $noreg, 8, $noreg :: (load 4
from %fixed-stack.0, align 16)
Remat created 1 dead defs.
Deleting dead def 16r   dead %0:gr32 = MOV32rm $rsp, 1, $noreg, 8, $noreg ::
(load 4 from %fixed-stack.0, align 16)
1 registers to spill after remat.
Merged spilled regs: SS#0 EMPTY  0@x weight:0.000000e+00
spillAroundUses %0
        folded:   32r   %1:gr32 = MOV32rm %stack.0, 1, $noreg, 0, $noreg :: (load 4 from %stack.0)

Afaict InlineSpiller is trying to add remats for the fixed-stack load. So it
inserts a load before the use inside the loop (start of bb.1), but since the
use in the COPY (in bb.0) is undef it isn't replaced by a remat, instead we get
a reload from a new spill slot. Although, there is no spill to the spill slot
(perhaps because the code thinks that we rematerialized all uses(?)).

Not sure where to solve this. Isn't it unfortunate to have these undef uses
(and dead defs) lingering around when doing the register allocation? Maybe we
could cleanup up those at the very beginning? Or should the remat be smarter
and replace the undef COPY with an IMPLICIT_DEF?
Quuxplusone commented 6 years ago

Attached remat-undef-use.mir (1199 bytes, text/plain): reduced reproducer