[llvm-dev] Assertion failure "There should be at least one conflict." in register coalescing

Harald van Dijk via llvm-dev llvm-dev at lists.llvm.org
Tue Oct 15 04:16:36 PDT 2019


Hi,

Please take a look at this MIR:

name: f
body: |
   bb.0:
     %0:gr64_with_sub_8bit = COPY $rax
     %1:gr32 = MOV32rr %0.sub_32bit:gr64_with_sub_8bit
     %2:gr32 = COPY %1:gr32
     %0.sub_32bit:gr64_with_sub_8bit = COPY %2:gr32
     %3:gr32 = MOV32rr %0.sub_32bit:gr64_with_sub_8bit
     %1:gr32 = MOV32rr %2:gr32
     %0.sub_32bit:gr64_with_sub_8bit = COPY %2:gr32

This is heavily reduced from real code, translated to X86 to rule out
the possibility of a bug in the target's register definitions.

When running the Simple Register Coalescing pass on this:

   llc -run-pass=simple-register-coalescing test.mir

It triggers an assert:

   llc: /home/harald/llvm/lib/CodeGen/RegisterCoalescer.cpp:2864: bool {anonymous}::JoinVals::resolveConflicts({anonymous}::JoinVals&): Assertion `!TaintExtent.empty() && "There should be at least one conflict."' failed.
   Stack dump:
   0.      Program arguments: llvm/build/bin/llc -run-pass=simple-register-coalescing testx86.mir
   1.      Running pass 'Function Pass Manager' on module 'testx86.mir'.
   2.      Running pass 'Simple Register Coalescing' on function '@f'
    #0 0x0000563febf583f3 llvm::sys::PrintStackTrace(llvm::raw_ostream&) /home/harald/llvm/lib/Support/Unix/Signals.inc:532:22
    #1 0x0000563febf58486 PrintStackTraceSignalHandler(void*) /home/harald/llvm/lib/Support/Unix/Signals.inc:593:1
    #2 0x0000563febf56334 llvm::sys::RunSignalHandlers() /home/harald/llvm/lib/Support/Signals.cpp:68:20
    #3 0x0000563febf57dac SignalHandler(int) /home/harald/llvm/lib/Support/Unix/Signals.inc:384:1
    #4 0x00007fdc53042f40 __restore_rt (/lib/x86_64-linux-gnu/libpthread.so.0+0x13f40)
    #5 0x00007fdc52aebed7 gsignal /build/glibc-KRRWSm/glibc-2.29/signal/../sysdeps/unix/sysv/linux/internal-signals.h:84:10
    #6 0x00007fdc52acd535 abort /build/glibc-KRRWSm/glibc-2.29/stdlib/abort.c:81:7
    #7 0x00007fdc52acd40f __tls_get_addr /build/glibc-KRRWSm/glibc-2.29/intl/loadmsgcat.c:1177:9
    #8 0x00007fdc52add012 (/lib/x86_64-linux-gnu/libc.so.6+0x35012)
    #9 0x0000563feb388d39 (anonymous namespace)::JoinVals::resolveConflicts((anonymous namespace)::JoinVals&) /home/harald/llvm/lib/CodeGen/RegisterCoalescer.cpp:2864:5
   #10 0x0000563feb38b2ee (anonymous namespace)::RegisterCoalescer::joinVirtRegs(llvm::CoalescerPair&) /home/harald/llvm/lib/CodeGen/RegisterCoalescer.cpp:3323:45
   #11 0x0000563feb38bc86 (anonymous namespace)::RegisterCoalescer::joinIntervals(llvm::CoalescerPair&) /home/harald/llvm/lib/CodeGen/RegisterCoalescer.cpp:3417:1
   #12 0x0000563feb3853f3 (anonymous namespace)::RegisterCoalescer::joinCopy(llvm::MachineInstr*, bool&) /home/harald/llvm/lib/CodeGen/RegisterCoalescer.cpp:1868:7
   #13 0x0000563feb38c1cf (anonymous namespace)::RegisterCoalescer::copyCoalesceWorkList(llvm::MutableArrayRef<llvm::MachineInstr*>) /home/harald/llvm/lib/CodeGen/RegisterCoalescer.cpp:3501:28
   #14 0x0000563feb38d0a9 (anonymous namespace)::RegisterCoalescer::joinAllIntervals() /home/harald/llvm/lib/CodeGen/RegisterCoalescer.cpp:3663:30
   #15 0x0000563feb38d3f0 (anonymous namespace)::RegisterCoalescer::runOnMachineFunction(llvm::MachineFunction&) /home/harald/llvm/lib/CodeGen/RegisterCoalescer.cpp:3710:17

This is with current LLVM trunk (r374866), but it is not new. When
running this with the Ubuntu-provided llc 8, it segfaults. Presumably
this has assertions disabled, and would have asserted otherwise.

Is this MIR valid? Does it contain something that Simple Register
Coalescing expects to have been removed by a previous pass already?

The extra output with -debug-only=regalloc is:

   Computing live-in reg-units in ABI blocks.
   Created 0 new intervals.
   ********** INTERVALS **********
   %0 [16r,64r:2)[64r,112r:1)[112r,112d:0)  0 at 112r 1 at 64r 2 at 16r weight:0.000000e+00
   %1 [32r,48r:1)[96r,96d:0)  0 at 96r 1 at 32r weight:0.000000e+00
   %2 [48r,112r:0)  0 at 48r weight:0.000000e+00
   %3 [80r,80d:0)  0 at 80r weight:0.000000e+00
   RegMasks:
   ********** MACHINEINSTRS **********
   # Machine code for function f: NoPHIs
   
   0B      bb.0:
   16B       %0:gr64_with_sub_8bit = COPY $rax
   32B       %1:gr32 = MOV32rr %0.sub_32bit:gr64_with_sub_8bit
   48B       %2:gr32 = COPY %1:gr32
   64B       %0.sub_32bit:gr64_with_sub_8bit = COPY %2:gr32
   80B       dead %3:gr32 = MOV32rr %0.sub_32bit:gr64_with_sub_8bit
   96B       dead %1:gr32 = MOV32rr %2:gr32
   112B      dead %0.sub_32bit:gr64_with_sub_8bit = COPY %2:gr32
   
   # End machine code for function f.
   
   ********** SIMPLE REGISTER COALESCING **********
   ********** Function: f
   ********** JOINING INTERVALS ***********
   :
   16B     %0:gr64_with_sub_8bit = COPY $rax
           Considering merging %0 with $rax
           Can only merge into reserved registers.
   48B     %2:gr32 = COPY %1:gr32
           Considering merging to GR32 with %2 in %1
                   RHS = %2 [48r,112r:0)  0 at 48r weight:0.000000e+00
                   LHS = %1 [32r,48r:1)[96r,96d:0)  0 at 96r 1 at 32r weight:0.000000e+00
                   merge %2:0 at 48r into %1:1 at 32r --> @32r
                   interference at %1:0 at 96r
           Interference!
   64B     %0.sub_32bit:gr64_with_sub_8bit = COPY %2:gr32
           Considering merging to GR64_with_sub_8bit with %2 in %0:sub_32bit
                   RHS = %2 [48r,112r:0)  0 at 48r weight:0.000000e+00
                   LHS = %0 [16r,64r:2)[64r,112r:1)[112r,112d:0)  0 at 112r 1 at 64r 2 at 16r weight:0.000000e+00
                   merge %0:1 at 64r into %2:0 at 48r --> @48r
                   merge %0:0 at 112r into %2:0 at 48r --> @48r
                   conflict at %2:0 at 48r
                   taints local %0:2 at 16r to 64r
                   pruned %0 at 48r: [16r,48r:2)[64r,112r:1)[112r,112d:0)  0 at 112r 1 at 64r 2 at 16r
                   erased: 112r    dead %0.sub_32bit:gr64_with_sub_8bit = COPY %2:gr32
                   erased: 64r     %0.sub_32bit:gr64_with_sub_8bit = COPY %2:gr32
                   restoring liveness to 2 points: 64r,48r:  %0 [16r,48r:0)[48r,112d:1)  0 at 16r 1 at 48r weight:0.000000e+00
   AllocationOrder(GR64) = [ $rax $rcx $rdx $rsi $rdi $r8 $r9 $r10 $r11 $rbx $r14 $r15 $r12 $r13 $rbp ]
   AllocationOrder(GR64_with_sub_8bit) = [ $rax $rcx $rdx $rsi $rdi $r8 $r9 $r10 $r11 $rbx $r14 $r15 $r12 $r13 $rbp ]
                   updated: 48B    %0.sub_32bit:gr64_with_sub_8bit = COPY %1:gr32
                   updated: 96B    dead %1:gr32 = MOV32rr %0.sub_32bit:gr64_with_sub_8bit
           Success: %2:sub_32bit -> %0
           Result = %0 [16r,48r:0)[48r,112d:1)  0 at 16r 1 at 48r weight:0.000000e+00
   48B     %0.sub_32bit:gr64_with_sub_8bit = COPY %1:gr32
           Considering merging to GR64_with_sub_8bit with %1 in %0:sub_32bit
                   RHS = %1 [32r,48r:1)[96r,96d:0)  0 at 96r 1 at 32r weight:0.000000e+00
                   LHS = %0 [16r,48r:0)[48r,112d:1)  0 at 16r 1 at 48r weight:0.000000e+00
                   merge %0:1 at 48r into %1:1 at 32r --> @32r
                   conflict at %1:0 at 96r
                   taints local %0:1 at 48r to 112d

I am trying to understand what this all means, but one thing that
strikes me is that if I manually update the MIR so that the first update
has been performed already:

   name: f
   body: |
     bb.0:
       %0:gr64_with_sub_8bit = COPY $rax
       %1:gr32 = MOV32rr %0.sub_32bit:gr64_with_sub_8bit
       %0.sub_32bit:gr64_with_sub_8bit = COPY %1:gr32
       %3:gr32 = MOV32rr %0.sub_32bit:gr64_with_sub_8bit
       %1:gr32 = MOV32rr %0.sub_32bit:gr64_with_sub_8bit

the pass does run successfully. However, the recalculated intervals are
not identical to what they were thought to be after the first update:

   ********** INTERVALS **********
   %0 [16r,48r:1)[48r,80r:0)  0 at 48r 1 at 16r weight:0.000000e+00
   %1 [32r,48r:1)[80r,80d:0)  0 at 80r 1 at 32r weight:0.000000e+00
   %2 [64r,64d:0)  0 at 64r weight:0.000000e+00

Note %0's [48r,80r:0) here, which was [48r,112d) after the initial
update. The instruction at 112 was
%0.sub_32bit:gr64_with_sub_8bit = COPY %2:gr32, which had been deleted.
Could that be the problem, the interval referring to a deleted
instruction?

Cheers,
Harald van Dijk


More information about the llvm-dev mailing list